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 instantiating
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     * @see SocketFactory
053     */
054    public abstract class SocketClient
055    {
056        /**
057         * The end of line character sequence used by most IETF protocols.  That
058         * is a carriage return followed by a newline: "\r\n"
059         */
060        public static final String NETASCII_EOL = "\r\n";
061    
062        /** The default SocketFactory shared by all SocketClient instances. */
063        private static final SocketFactory __DEFAULT_SOCKET_FACTORY =
064                SocketFactory.getDefault();
065    
066        /** The default {@link ServerSocketFactory} */
067        private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY =
068                ServerSocketFactory.getDefault();
069    
070        /**
071         * A ProtocolCommandSupport object used to manage the registering of
072         * ProtocolCommandListeners and te firing of ProtocolCommandEvents.
073         */
074        private ProtocolCommandSupport __commandSupport;
075    
076        /** The timeout to use after opening a socket. */
077        protected int _timeout_;
078    
079        /** The socket used for the connection. */
080        protected Socket _socket_;
081    
082        /** The default port the client should connect to. */
083        protected int _defaultPort_;
084    
085        /** The socket's InputStream. */
086        protected InputStream _input_;
087    
088        /** The socket's OutputStream. */
089        protected OutputStream _output_;
090    
091        /** The socket's SocketFactory. */
092        protected SocketFactory _socketFactory_;
093    
094        /** The socket's ServerSocket Factory. */
095        protected ServerSocketFactory _serverSocketFactory_;
096    
097        /** The socket's connect timeout (0 = infinite timeout) */
098        private static final int DEFAULT_CONNECT_TIMEOUT = 0;
099        protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
100    
101        /** Hint for SO_RCVBUF size */
102        private int receiveBufferSize = -1;
103    
104        /** Hint for SO_SNDBUF size */
105        private int sendBufferSize = -1;
106    
107        /**
108         * Default constructor for SocketClient.  Initializes
109         * _socket_ to null, _timeout_ to 0, _defaultPort to 0,
110         * _isConnected_ to false, and _socketFactory_ to a shared instance of
111         * {@link org.apache.commons.net.DefaultSocketFactory}.
112         */
113        public SocketClient()
114        {
115            _socket_ = null;
116            _input_ = null;
117            _output_ = null;
118            _timeout_ = 0;
119            _defaultPort_ = 0;
120            _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
121            _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY;
122        }
123    
124    
125        /**
126         * Because there are so many connect() methods, the _connectAction_()
127         * method is provided as a means of performing some action immediately
128         * after establishing a connection, rather than reimplementing all
129         * of the connect() methods.  The last action performed by every
130         * connect() method after opening a socket is to call this method.
131         * <p>
132         * This method sets the timeout on the just opened socket to the default
133         * timeout set by {@link #setDefaultTimeout  setDefaultTimeout() },
134         * sets _input_ and _output_ to the socket's InputStream and OutputStream
135         * respectively, and sets _isConnected_ to true.
136         * <p>
137         * Subclasses overriding this method should start by calling
138         * <code> super._connectAction_() </code> first to ensure the
139         * initialization of the aforementioned protected variables.
140         */
141        protected void _connectAction_() throws IOException
142        {
143            _socket_.setSoTimeout(_timeout_);
144            _input_ = _socket_.getInputStream();
145            _output_ = _socket_.getOutputStream();
146        }
147    
148    
149        /**
150         * Opens a Socket connected to a remote host at the specified port and
151         * originating from the current host at a system assigned port.
152         * Before returning, {@link #_connectAction_  _connectAction_() }
153         * is called to perform connection initialization actions.
154         * <p>
155         * @param host  The remote host.
156         * @param port  The port to connect to on the remote host.
157         * @exception SocketException If the socket timeout could not be set.
158         * @exception IOException If the socket could not be opened.  In most
159         *  cases you will only want to catch IOException since SocketException is
160         *  derived from it.
161         */
162        public void connect(InetAddress host, int port)
163        throws SocketException, IOException
164        {
165            _socket_ = _socketFactory_.createSocket();
166            if (receiveBufferSize != -1) _socket_.setReceiveBufferSize(receiveBufferSize);
167            if (sendBufferSize != -1) _socket_.setSendBufferSize(sendBufferSize);
168            _socket_.connect(new InetSocketAddress(host, port), connectTimeout);
169            _connectAction_();
170        }
171    
172        /**
173         * Opens a Socket connected to a remote host at the specified port and
174         * originating from the current host at a system assigned port.
175         * Before returning, {@link #_connectAction_  _connectAction_() }
176         * is called to perform connection initialization actions.
177         * <p>
178         * @param hostname  The name of the remote host.
179         * @param port  The port to connect to on the remote host.
180         * @exception SocketException If the socket timeout could not be set.
181         * @exception IOException If the socket could not be opened.  In most
182         *  cases you will only want to catch IOException since SocketException is
183         *  derived from it.
184         * @exception UnknownHostException If the hostname cannot be resolved.
185         */
186        public void connect(String hostname, int port)
187        throws SocketException, IOException
188        {
189            connect(InetAddress.getByName(hostname), port);
190        }
191    
192    
193        /**
194         * Opens a Socket connected to a remote host at the specified port and
195         * originating from the specified local address and port.
196         * Before returning, {@link #_connectAction_  _connectAction_() }
197         * is called to perform connection initialization actions.
198         * <p>
199         * @param host  The remote host.
200         * @param port  The port to connect to on the remote host.
201         * @param localAddr  The local address to use.
202         * @param localPort  The local port to use.
203         * @exception SocketException If the socket timeout could not be set.
204         * @exception IOException If the socket could not be opened.  In most
205         *  cases you will only want to catch IOException since SocketException is
206         *  derived from it.
207         */
208        public void connect(InetAddress host, int port,
209                            InetAddress localAddr, int localPort)
210        throws SocketException, IOException
211        {
212            _socket_ = _socketFactory_.createSocket();
213            if (receiveBufferSize != -1) _socket_.setReceiveBufferSize(receiveBufferSize);
214            if (sendBufferSize != -1) _socket_.setSendBufferSize(sendBufferSize);
215            _socket_.bind(new InetSocketAddress(localAddr, localPort));
216            _socket_.connect(new InetSocketAddress(host, port), connectTimeout);
217            _connectAction_();
218        }
219    
220    
221        /**
222         * Opens a Socket connected to a remote host at the specified port and
223         * originating from the specified local address and port.
224         * Before returning, {@link #_connectAction_  _connectAction_() }
225         * is called to perform connection initialization actions.
226         * <p>
227         * @param hostname  The name of the remote host.
228         * @param port  The port to connect to on the remote host.
229         * @param localAddr  The local address to use.
230         * @param localPort  The local port to use.
231         * @exception SocketException If the socket timeout could not be set.
232         * @exception IOException If the socket could not be opened.  In most
233         *  cases you will only want to catch IOException since SocketException is
234         *  derived from it.
235         * @exception UnknownHostException If the hostname cannot be resolved.
236         */
237        public void connect(String hostname, int port,
238                            InetAddress localAddr, int localPort)
239        throws SocketException, IOException
240        {
241           connect(InetAddress.getByName(hostname), port, localAddr, localPort);
242        }
243    
244    
245        /**
246         * Opens a Socket connected to a remote host at the current default port
247         * and originating from the current host at a system assigned port.
248         * Before returning, {@link #_connectAction_  _connectAction_() }
249         * is called to perform connection initialization actions.
250         * <p>
251         * @param host  The remote host.
252         * @exception SocketException If the socket timeout could not be set.
253         * @exception IOException If the socket could not be opened.  In most
254         *  cases you will only want to catch IOException since SocketException is
255         *  derived from it.
256         */
257        public void connect(InetAddress host) throws SocketException, IOException
258        {
259            connect(host, _defaultPort_);
260        }
261    
262    
263        /**
264         * Opens a Socket connected to a remote host at the current default
265         * port and originating from the current host at a system assigned port.
266         * Before returning, {@link #_connectAction_  _connectAction_() }
267         * is called to perform connection initialization actions.
268         * <p>
269         * @param hostname  The name of the remote host.
270         * @exception SocketException If the socket timeout could not be set.
271         * @exception IOException If the socket could not be opened.  In most
272         *  cases you will only want to catch IOException since SocketException is
273         *  derived from it.
274         * @exception UnknownHostException If the hostname cannot be resolved.
275         */
276        public void connect(String hostname) throws SocketException, IOException
277        {
278            connect(hostname, _defaultPort_);
279        }
280    
281    
282        /**
283         * Disconnects the socket connection.
284         * You should call this method after you've finished using the class
285         * instance and also before you call
286         * {@link #connect connect() }
287         * again.  _isConnected_ is set to false, _socket_ is set to null,
288         * _input_ is set to null, and _output_ is set to null.
289         * <p>
290         * @exception IOException  If there is an error closing the socket.
291         */
292        public void disconnect() throws IOException
293        {
294            closeQuietly(_socket_);
295            closeQuietly(_input_);
296            closeQuietly(_output_);
297            _socket_ = null;
298            _input_ = null;
299            _output_ = null;
300        }
301    
302        private void closeQuietly(Socket socket) {
303            if (socket != null){
304                try {
305                    socket.close();
306                } catch (IOException e) {
307                }
308            }
309        }
310    
311        private void closeQuietly(Closeable close){
312            if (close != null){
313                try {
314                    close.close();
315                } catch (IOException e) {
316                }
317            }
318        }
319        /**
320         * Returns true if the client is currently connected to a server.
321         * <p>
322         * Delegates to {@link Socket#isConnected()}
323         * @return True if the client is currently connected to a server,
324         *         false otherwise.
325         */
326        public boolean isConnected()
327        {
328            if (_socket_ == null)
329                return false;
330    
331            return _socket_.isConnected();
332        }
333    
334        /**
335         * Make various checks on the socket to test if it is available for use.
336         * Note that the only sure test is to use it, but these checks may help
337         * in some cases.
338         * @see <a href="https://issues.apache.org/jira/browse/NET-350">NET-350</a>
339         * @return {@code true} if the socket appears to be available for use
340         * @since 3.0
341         */
342        public boolean isAvailable(){
343            if (isConnected()) {
344                try
345                {
346                    if (_socket_.getInetAddress() == null) return false;
347                    if (_socket_.getPort() == 0) return false;
348                    if (_socket_.getRemoteSocketAddress() == null) return false;
349                    if (_socket_.isClosed()) return false;
350                    /* these aren't exact checks (a Socket can be half-open),
351                       but since we usually require two-way data transfer,
352                       we check these here too: */
353                    if (_socket_.isInputShutdown()) return false;
354                    if (_socket_.isOutputShutdown()) return false;
355                    /* ignore the result, catch exceptions: */
356                    _socket_.getInputStream();
357                    _socket_.getOutputStream();
358                }
359                catch (IOException ioex)
360                {
361                    return false;
362                }
363                return true;
364            } else {
365                return false;
366            }
367        }
368    
369        /**
370         * Sets the default port the SocketClient should connect to when a port
371         * is not specified.  The {@link #_defaultPort_  _defaultPort_ }
372         * variable stores this value.  If never set, the default port is equal
373         * to zero.
374         * <p>
375         * @param port  The default port to set.
376         */
377        public void setDefaultPort(int port)
378        {
379            _defaultPort_ = port;
380        }
381    
382        /**
383         * Returns the current value of the default port (stored in
384         * {@link #_defaultPort_  _defaultPort_ }).
385         * <p>
386         * @return The current value of the default port.
387         */
388        public int getDefaultPort()
389        {
390            return _defaultPort_;
391        }
392    
393    
394        /**
395         * Set the default timeout in milliseconds to use when opening a socket.
396         * This value is only used previous to a call to
397         * {@link #connect connect()}
398         * and should not be confused with {@link #setSoTimeout setSoTimeout()}
399         * which operates on an the currently opened socket.  _timeout_ contains
400         * the new timeout value.
401         * <p>
402         * @param timeout  The timeout in milliseconds to use for the socket
403         *                 connection.
404         */
405        public void setDefaultTimeout(int timeout)
406        {
407            _timeout_ = timeout;
408        }
409    
410    
411        /**
412         * Returns the default timeout in milliseconds that is used when
413         * opening a socket.
414         * <p>
415         * @return The default timeout in milliseconds that is used when
416         *         opening a socket.
417         */
418        public int getDefaultTimeout()
419        {
420            return _timeout_;
421        }
422    
423    
424        /**
425         * Set the timeout in milliseconds of a currently open connection.
426         * Only call this method after a connection has been opened
427         * by {@link #connect connect()}.
428         * <p>
429         * @param timeout  The timeout in milliseconds to use for the currently
430         *                 open socket connection.
431         * @exception SocketException If the operation fails.
432         */
433        public void setSoTimeout(int timeout) throws SocketException
434        {
435            _socket_.setSoTimeout(timeout);
436        }
437    
438    
439        /**
440         * Set the underlying socket send buffer size.
441         * <p>
442         * @param size The size of the buffer in bytes.
443         * @throws SocketException
444         * @since 2.0
445         */
446        public void setSendBufferSize(int size) throws SocketException {
447            sendBufferSize = size;
448        }
449    
450        /**
451         * Get the current sendBuffer size
452         * @return the size, or -1 if not initialised
453         * @since 3.0 
454         */
455        protected int getSendBufferSize(){
456            return sendBufferSize;
457        }
458    
459        /**
460         * Sets the underlying socket receive buffer size.
461         * <p>
462         * @param size The size of the buffer in bytes.
463         * @throws SocketException
464         * @since 2.0
465         */
466        public void setReceiveBufferSize(int size) throws SocketException  {
467            receiveBufferSize = size;
468        }
469    
470        /**
471         * Get the current receivedBuffer size
472         * @return the size, or -1 if not initialised
473         * @since 3.0 
474         */
475        protected int getReceiveBufferSize(){
476            return receiveBufferSize;
477        }
478    
479        /**
480         * Returns the timeout in milliseconds of the currently opened socket.
481         * <p>
482         * @return The timeout in milliseconds of the currently opened socket.
483         * @exception SocketException If the operation fails.
484         */
485        public int getSoTimeout() throws SocketException
486        {
487            return _socket_.getSoTimeout();
488        }
489    
490        /**
491         * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the
492         * currently opened socket.
493         * <p>
494         * @param on  True if Nagle's algorithm is to be enabled, false if not.
495         * @exception SocketException If the operation fails.
496         */
497        public void setTcpNoDelay(boolean on) throws SocketException
498        {
499            _socket_.setTcpNoDelay(on);
500        }
501    
502    
503        /**
504         * Returns true if Nagle's algorithm is enabled on the currently opened
505         * socket.
506         * <p>
507         * @return True if Nagle's algorithm is enabled on the currently opened
508         *        socket, false otherwise.
509         * @exception SocketException If the operation fails.
510         */
511        public boolean getTcpNoDelay() throws SocketException
512        {
513            return _socket_.getTcpNoDelay();
514        }
515    
516        /**
517         * Sets the SO_KEEPALIVE flag on the currently opened socket.
518         *
519         * From the Javadocs, the default keepalive time is 2 hours (although this is
520         * implementation  dependent). It looks as though the Windows WSA sockets implementation
521         * allows a specific keepalive value to be set, although this seems not to be the case on
522         * other systems.
523         * @param  keepAlive If true, keepAlive is turned on
524         * @throws SocketException
525         * @since 2.2
526         */
527        public void setKeepAlive(boolean keepAlive) throws SocketException {
528            _socket_.setKeepAlive(keepAlive);
529        }
530    
531        /**
532         * Returns the current value of the SO_KEEPALIVE flag on the currently opened socket.
533         * Delegates to {@link Socket#getKeepAlive()}
534         * @return True if SO_KEEPALIVE is enabled.
535         * @throws SocketException
536         * @since 2.2
537         */
538        public boolean getKeepAlive() throws SocketException {
539            return _socket_.getKeepAlive();
540        }
541    
542        /**
543         * Sets the SO_LINGER timeout on the currently opened socket.
544         * <p>
545         * @param on  True if linger is to be enabled, false if not.
546         * @param val The linger timeout (in hundredths of a second?)
547         * @exception SocketException If the operation fails.
548         */
549        public void setSoLinger(boolean on, int val) throws SocketException
550        {
551            _socket_.setSoLinger(on, val);
552        }
553    
554    
555        /**
556         * Returns the current SO_LINGER timeout of the currently opened socket.
557         * <p>
558         * @return The current SO_LINGER timeout.  If SO_LINGER is disabled returns
559         *         -1.
560         * @exception SocketException If the operation fails.
561         */
562        public int getSoLinger() throws SocketException
563        {
564            return _socket_.getSoLinger();
565        }
566    
567    
568        /**
569         * Returns the port number of the open socket on the local host used
570         * for the connection.
571         * Delegates to {@link Socket#getLocalPort()}
572         * <p>
573         * @return The port number of the open socket on the local host used
574         *         for the connection.
575         */
576        public int getLocalPort()
577        {
578            return _socket_.getLocalPort();
579        }
580    
581    
582        /**
583         * Returns the local address  to which the client's socket is bound.
584         * Delegates to {@link Socket#getLocalAddress()}
585         * <p>
586         * @return The local address to which the client's socket is bound.
587         */
588        public InetAddress getLocalAddress()
589        {
590            return _socket_.getLocalAddress();
591        }
592    
593        /**
594         * Returns the port number of the remote host to which the client is
595         * connected.
596         * Delegates to {@link Socket#getPort()}
597         * <p>
598         * @return The port number of the remote host to which the client is
599         *         connected.
600         */
601        public int getRemotePort()
602        {
603            return _socket_.getPort();
604        }
605    
606    
607        /**
608         * @return The remote address to which the client is connected.
609         * Delegates to {@link Socket#getInetAddress()}
610         */
611        public InetAddress getRemoteAddress()
612        {
613            return _socket_.getInetAddress();
614        }
615    
616    
617        /**
618         * Verifies that the remote end of the given socket is connected to the
619         * the same host that the SocketClient is currently connected to.  This
620         * is useful for doing a quick security check when a client needs to
621         * accept a connection from a server, such as an FTP data connection or
622         * a BSD R command standard error stream.
623         * <p>
624         * @return True if the remote hosts are the same, false if not.
625         */
626        public boolean verifyRemote(Socket socket)
627        {
628            InetAddress host1, host2;
629    
630            host1 = socket.getInetAddress();
631            host2 = getRemoteAddress();
632    
633            return host1.equals(host2);
634        }
635    
636    
637        /**
638         * Sets the SocketFactory used by the SocketClient to open socket
639         * connections.  If the factory value is null, then a default
640         * factory is used (only do this to reset the factory after having
641         * previously altered it).
642         * <p>
643         * @param factory  The new SocketFactory the SocketClient should use.
644         */
645        public void setSocketFactory(SocketFactory factory)
646        {
647            if (factory == null)
648                _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
649            else
650                _socketFactory_ = factory;
651        }
652    
653        /**
654         * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket
655         * connections.  If the factory value is null, then a default
656         * factory is used (only do this to reset the factory after having
657         * previously altered it).
658         * <p>
659         * @param factory  The new ServerSocketFactory the SocketClient should use.
660         * @since 2.0
661         */
662        public void setServerSocketFactory(ServerSocketFactory factory) {
663            if (factory == null)
664                _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY;
665            else
666                _serverSocketFactory_ = factory;
667        }
668    
669        /**
670         * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's
671         * connect() method.
672         * @param connectTimeout The connection timeout to use (in ms)
673         * @since 2.0
674         */
675        public void setConnectTimeout(int connectTimeout) {
676            this.connectTimeout = connectTimeout;
677        }
678    
679        /**
680         * Get the underlying socket connection timeout.
681         * @return timeout (in ms)
682         * @since 2.0
683         */
684        public int getConnectTimeout() {
685            return connectTimeout;
686        }
687    
688        /**
689         * Get the underlying {@link ServerSocketFactory}
690         * @return The server socket factory
691         * @since 2.2
692         */
693        public ServerSocketFactory getServerSocketFactory() {
694            return _serverSocketFactory_;
695        }
696    
697    
698        /**
699         * Adds a ProtocolCommandListener. 
700         *
701         * @param listener  The ProtocolCommandListener to add.
702         * @since 3.0
703         */
704        public void addProtocolCommandListener(ProtocolCommandListener listener) {
705            getCommandSupport().addProtocolCommandListener(listener);
706        }
707    
708        /**
709         * Removes a ProtocolCommandListener.
710         *
711         * @param listener  The ProtocolCommandListener to remove.
712         * @since 3.0
713         */
714        public void removeProtocolCommandListener(ProtocolCommandListener listener) {
715            getCommandSupport().removeProtocolCommandListener(listener);
716        }
717    
718        /**
719         * If there are any listeners, send them the reply details.
720         * 
721         * @param replyCode the code extracted from the reply
722         * @param reply the full reply text
723         * @since 3.0
724         */
725        protected void fireReplyReceived(int replyCode, String reply) {
726            if (getCommandSupport().getListenerCount() > 0) {
727                getCommandSupport().fireReplyReceived(replyCode, reply);
728            }
729        }
730    
731        /**
732         * If there are any listeners, send them the command details.
733         * 
734         * @param command the command name
735         * @param message the complete message, including command name
736         * @since 3.0
737         */
738        protected void fireCommandSent(String command, String message) {
739            if (getCommandSupport().getListenerCount() > 0) {
740                getCommandSupport().fireCommandSent(command, message);
741            }
742        }
743    
744        /**
745         * Create the CommandSupport instance if required
746         */
747        protected void createCommandSupport(){
748            __commandSupport = new ProtocolCommandSupport(this);
749        }
750    
751        /**
752         * Subclasses can override this if they need to provide their own
753         * instance field for backwards compatibilty.
754         * 
755         * @return the CommandSupport instance, may be {@code null}
756         * @since 3.0
757         */
758        protected ProtocolCommandSupport getCommandSupport() {
759            return __commandSupport;
760        }
761    
762        /*
763         *  N.B. Fields cannot be pulled up into a super-class without breaking binary compatibility,
764         *  so the abstract method is needed to pass the instance to the methods which were moved here.
765         */
766    }
767    
768