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