1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.net.InetAddress;
24 import java.net.InetSocketAddress;
25 import java.net.Proxy;
26 import java.net.Socket;
27 import java.net.SocketException;
28 import java.nio.charset.Charset;
29 import java.util.Objects;
30
31 import javax.net.ServerSocketFactory;
32 import javax.net.SocketFactory;
33
34 import org.apache.commons.io.IOUtils;
35
36 /**
37 * 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
38 * 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}
39 * method, which allows you to control the type of Socket the SocketClient creates for initiating network connections. This is especially useful for adding SSL
40 * or proxy support as well as better support for applets. For example, you could create a {@link javax.net.SocketFactory} that requests browser security
41 * capabilities before creating a socket. All classes derived from SocketClient should use the {@link #_socketFactory_ _socketFactory_} member variable to
42 * create Socket and ServerSocket instances rather than instantiating them by directly invoking a constructor. By honoring this contract you guarantee that a
43 * user will always be able to provide his own Socket implementations by substituting his own SocketFactory.
44 *
45 * @see SocketFactory
46 */
47 public abstract class SocketClient {
48
49 /**
50 * The end of line character sequence used by most IETF protocols. That is a carriage return followed by a newline: "\r\n"
51 */
52 public static final String NETASCII_EOL = "\r\n";
53
54 /** The default SocketFactory shared by all SocketClient instances. */
55 private static final SocketFactory DEFAULT_SOCKET_FACTORY = SocketFactory.getDefault();
56
57 /** The default {@link ServerSocketFactory} */
58 private static final ServerSocketFactory DEFAULT_SERVER_SOCKET_FACTORY = ServerSocketFactory.getDefault();
59
60 /** The socket's connect timeout (0 = infinite timeout) */
61 private static final int DEFAULT_CONNECT_TIMEOUT = 60000;
62
63 /**
64 * Gets the IP address string of the given Socket in textual presentation.
65 *
66 * @param socket the socket to query.
67 * @return the raw IP address in a string format.
68 * @since 3.12.0
69 */
70 protected static String getHostAddress(final Socket socket) {
71 return getHostAddress(socket.getInetAddress());
72 }
73
74 /**
75 * Gets the IP address string of the given InetAddress in textual presentation.
76 *
77 * @param inetAddress Internet Protocol (IP) address to query.
78 * @return the raw IP address in a string format.
79 * @since 3.12.0
80 */
81 protected static String getHostAddress(final InetAddress inetAddress) {
82 return inetAddress != null ? inetAddress.getHostAddress() : null;
83 }
84
85 /**
86 * A ProtocolCommandSupport object used to manage the registering of ProtocolCommandListeners and the firing of ProtocolCommandEvents.
87 */
88 private ProtocolCommandSupport commandSupport;
89
90 /** The timeout to use after opening a socket. */
91 protected int _timeout_;
92
93 /** The socket used for the connection. */
94 protected Socket _socket_;
95
96 /** The hostname used for the connection (null = no hostname supplied). */
97 protected String _hostname_;
98
99 /** 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 }