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