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