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