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