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