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 instanting 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 * @author Daniel F. Savarese 053 * @see SocketFactory 054 */ 055 public abstract class SocketClient 056 { 057 /** 058 * The end of line character sequence used by most IETF protocols. That 059 * is a carriage return followed by a newline: "\r\n" 060 */ 061 public static final String NETASCII_EOL = "\r\n"; 062 063 /** The default SocketFactory shared by all SocketClient instances. */ 064 private static final SocketFactory __DEFAULT_SOCKET_FACTORY = 065 SocketFactory.getDefault(); 066 067 /** The default {@link ServerSocketFactory} */ 068 private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY = 069 ServerSocketFactory.getDefault(); 070 071 /** The timeout to use after opening a socket. */ 072 protected int _timeout_; 073 074 /** The socket used for the connection. */ 075 protected Socket _socket_; 076 077 /** The default port the client should connect to. */ 078 protected int _defaultPort_; 079 080 /** The socket's InputStream. */ 081 protected InputStream _input_; 082 083 /** The socket's OutputStream. */ 084 protected OutputStream _output_; 085 086 /** The socket's SocketFactory. */ 087 protected SocketFactory _socketFactory_; 088 089 /** The socket's ServerSocket Factory. */ 090 protected ServerSocketFactory _serverSocketFactory_; 091 092 /** The socket's connect timeout (0 = infinite timeout) */ 093 private static final int DEFAULT_CONNECT_TIMEOUT = 0; 094 protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT; 095 096 /** Hint for SO_RCVBUF size */ 097 int receiveBufferSize = -1; 098 099 /** Hint for SO_SNDBUF size */ 100 int sendBufferSize = -1; 101 102 /** 103 * Default constructor for SocketClient. Initializes 104 * _socket_ to null, _timeout_ to 0, _defaultPort to 0, 105 * _isConnected_ to false, and _socketFactory_ to a shared instance of 106 * {@link org.apache.commons.net.DefaultSocketFactory}. 107 */ 108 public SocketClient() 109 { 110 _socket_ = null; 111 _input_ = null; 112 _output_ = null; 113 _timeout_ = 0; 114 _defaultPort_ = 0; 115 _socketFactory_ = __DEFAULT_SOCKET_FACTORY; 116 _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; 117 } 118 119 120 /** 121 * Because there are so many connect() methods, the _connectAction_() 122 * method is provided as a means of performing some action immediately 123 * after establishing a connection, rather than reimplementing all 124 * of the connect() methods. The last action performed by every 125 * connect() method after opening a socket is to call this method. 126 * <p> 127 * This method sets the timeout on the just opened socket to the default 128 * timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, 129 * sets _input_ and _output_ to the socket's InputStream and OutputStream 130 * respectively, and sets _isConnected_ to true. 131 * <p> 132 * Subclasses overriding this method should start by calling 133 * <code> super._connectAction_() </code> first to ensure the 134 * initialization of the aforementioned protected variables. 135 */ 136 protected void _connectAction_() throws IOException 137 { 138 _socket_.setSoTimeout(_timeout_); 139 _input_ = _socket_.getInputStream(); 140 _output_ = _socket_.getOutputStream(); 141 } 142 143 144 /** 145 * Opens a Socket connected to a remote host at the specified port and 146 * originating from the current host at a system assigned port. 147 * Before returning, {@link #_connectAction_ _connectAction_() } 148 * is called to perform connection initialization actions. 149 * <p> 150 * @param host The remote host. 151 * @param port The port to connect to on the remote host. 152 * @exception SocketException If the socket timeout could not be set. 153 * @exception IOException If the socket could not be opened. In most 154 * cases you will only want to catch IOException since SocketException is 155 * derived from it. 156 */ 157 public void connect(InetAddress host, int port) 158 throws SocketException, IOException 159 { 160 _socket_ = _socketFactory_.createSocket(); 161 if (receiveBufferSize != -1) _socket_.setReceiveBufferSize(receiveBufferSize); 162 if (sendBufferSize != -1) _socket_.setSendBufferSize(sendBufferSize); 163 _socket_.connect(new InetSocketAddress(host, port), connectTimeout); 164 _connectAction_(); 165 } 166 167 /** 168 * Opens a Socket connected to a remote host at the specified port and 169 * originating from the current host at a system assigned port. 170 * Before returning, {@link #_connectAction_ _connectAction_() } 171 * is called to perform connection initialization actions. 172 * <p> 173 * @param hostname The name of the remote host. 174 * @param port The port to connect to on the remote host. 175 * @exception SocketException If the socket timeout could not be set. 176 * @exception IOException If the socket could not be opened. In most 177 * cases you will only want to catch IOException since SocketException is 178 * derived from it. 179 * @exception UnknownHostException If the hostname cannot be resolved. 180 */ 181 public void connect(String hostname, int port) 182 throws SocketException, IOException 183 { 184 connect(InetAddress.getByName(hostname), port); 185 } 186 187 188 /** 189 * Opens a Socket connected to a remote host at the specified port and 190 * originating from the specified local address and port. 191 * Before returning, {@link #_connectAction_ _connectAction_() } 192 * is called to perform connection initialization actions. 193 * <p> 194 * @param host The remote host. 195 * @param port The port to connect to on the remote host. 196 * @param localAddr The local address to use. 197 * @param localPort The local port to use. 198 * @exception SocketException If the socket timeout could not be set. 199 * @exception IOException If the socket could not be opened. In most 200 * cases you will only want to catch IOException since SocketException is 201 * derived from it. 202 */ 203 public void connect(InetAddress host, int port, 204 InetAddress localAddr, int localPort) 205 throws SocketException, IOException 206 { 207 _socket_ = _socketFactory_.createSocket(); 208 if (receiveBufferSize != -1) _socket_.setReceiveBufferSize(receiveBufferSize); 209 if (sendBufferSize != -1) _socket_.setSendBufferSize(sendBufferSize); 210 _socket_.bind(new InetSocketAddress(localAddr, localPort)); 211 _socket_.connect(new InetSocketAddress(host, port), connectTimeout); 212 _connectAction_(); 213 } 214 215 216 /** 217 * Opens a Socket connected to a remote host at the specified port and 218 * originating from the specified local address and port. 219 * Before returning, {@link #_connectAction_ _connectAction_() } 220 * is called to perform connection initialization actions. 221 * <p> 222 * @param hostname The name of the remote host. 223 * @param port The port to connect to on the remote host. 224 * @param localAddr The local address to use. 225 * @param localPort The local port to use. 226 * @exception SocketException If the socket timeout could not be set. 227 * @exception IOException If the socket could not be opened. In most 228 * cases you will only want to catch IOException since SocketException is 229 * derived from it. 230 * @exception UnknownHostException If the hostname cannot be resolved. 231 */ 232 public void connect(String hostname, int port, 233 InetAddress localAddr, int localPort) 234 throws SocketException, IOException 235 { 236 connect(InetAddress.getByName(hostname), port, localAddr, localPort); 237 } 238 239 240 /** 241 * Opens a Socket connected to a remote host at the current default port 242 * and originating from the current host at a system assigned port. 243 * Before returning, {@link #_connectAction_ _connectAction_() } 244 * is called to perform connection initialization actions. 245 * <p> 246 * @param host The remote host. 247 * @exception SocketException If the socket timeout could not be set. 248 * @exception IOException If the socket could not be opened. In most 249 * cases you will only want to catch IOException since SocketException is 250 * derived from it. 251 */ 252 public void connect(InetAddress host) throws SocketException, IOException 253 { 254 connect(host, _defaultPort_); 255 } 256 257 258 /** 259 * Opens a Socket connected to a remote host at the current default 260 * port and originating from the current host at a system assigned port. 261 * Before returning, {@link #_connectAction_ _connectAction_() } 262 * is called to perform connection initialization actions. 263 * <p> 264 * @param hostname The name of the remote host. 265 * @exception SocketException If the socket timeout could not be set. 266 * @exception IOException If the socket could not be opened. In most 267 * cases you will only want to catch IOException since SocketException is 268 * derived from it. 269 * @exception UnknownHostException If the hostname cannot be resolved. 270 */ 271 public void connect(String hostname) throws SocketException, IOException 272 { 273 connect(hostname, _defaultPort_); 274 } 275 276 277 /** 278 * Disconnects the socket connection. 279 * You should call this method after you've finished using the class 280 * instance and also before you call 281 * {@link #connect connect() } 282 * again. _isConnected_ is set to false, _socket_ is set to null, 283 * _input_ is set to null, and _output_ is set to null. 284 * <p> 285 * @exception IOException If there is an error closing the socket. 286 */ 287 public void disconnect() throws IOException 288 { 289 closeQuietly(_socket_); 290 closeQuietly(_input_); 291 closeQuietly(_output_); 292 _socket_ = null; 293 _input_ = null; 294 _output_ = null; 295 } 296 297 private void closeQuietly(Socket socket) { 298 if (socket != null){ 299 try { 300 socket.close(); 301 } catch (IOException e) { 302 } 303 } 304 } 305 306 private void closeQuietly(Closeable close){ 307 if (close != null){ 308 try { 309 close.close(); 310 } catch (IOException e) { 311 } 312 } 313 } 314 /** 315 * Returns true if the client is currently connected to a server. 316 * <p> 317 * @return True if the client is currently connected to a server, 318 * false otherwise. 319 */ 320 public boolean isConnected() 321 { 322 if (_socket_ == null) 323 return false; 324 325 return _socket_.isConnected(); 326 } 327 328 329 /** 330 * Sets the default port the SocketClient should connect to when a port 331 * is not specified. The {@link #_defaultPort_ _defaultPort_ } 332 * variable stores this value. If never set, the default port is equal 333 * to zero. 334 * <p> 335 * @param port The default port to set. 336 */ 337 public void setDefaultPort(int port) 338 { 339 _defaultPort_ = port; 340 } 341 342 /** 343 * Returns the current value of the default port (stored in 344 * {@link #_defaultPort_ _defaultPort_ }). 345 * <p> 346 * @return The current value of the default port. 347 */ 348 public int getDefaultPort() 349 { 350 return _defaultPort_; 351 } 352 353 354 /** 355 * Set the default timeout in milliseconds to use when opening a socket. 356 * This value is only used previous to a call to 357 * {@link #connect connect()} 358 * and should not be confused with {@link #setSoTimeout setSoTimeout()} 359 * which operates on an the currently opened socket. _timeout_ contains 360 * the new timeout value. 361 * <p> 362 * @param timeout The timeout in milliseconds to use for the socket 363 * connection. 364 */ 365 public void setDefaultTimeout(int timeout) 366 { 367 _timeout_ = timeout; 368 } 369 370 371 /** 372 * Returns the default timeout in milliseconds that is used when 373 * opening a socket. 374 * <p> 375 * @return The default timeout in milliseconds that is used when 376 * opening a socket. 377 */ 378 public int getDefaultTimeout() 379 { 380 return _timeout_; 381 } 382 383 384 /** 385 * Set the timeout in milliseconds of a currently open connection. 386 * Only call this method after a connection has been opened 387 * by {@link #connect connect()}. 388 * <p> 389 * @param timeout The timeout in milliseconds to use for the currently 390 * open socket connection. 391 * @exception SocketException If the operation fails. 392 */ 393 public void setSoTimeout(int timeout) throws SocketException 394 { 395 _socket_.setSoTimeout(timeout); 396 } 397 398 399 /** 400 * Set the underlying socket send buffer size. 401 * <p> 402 * @param size The size of the buffer in bytes. 403 * @throws SocketException 404 * @since 2.0 405 */ 406 public void setSendBufferSize(int size) throws SocketException { 407 sendBufferSize = size; 408 } 409 410 411 /** 412 * Sets the underlying socket receive buffer size. 413 * <p> 414 * @param size The size of the buffer in bytes. 415 * @throws SocketException 416 * @since 2.0 417 */ 418 public void setReceiveBufferSize(int size) throws SocketException { 419 receiveBufferSize = size; 420 } 421 422 423 /** 424 * Returns the timeout in milliseconds of the currently opened socket. 425 * <p> 426 * @return The timeout in milliseconds of the currently opened socket. 427 * @exception SocketException If the operation fails. 428 */ 429 public int getSoTimeout() throws SocketException 430 { 431 return _socket_.getSoTimeout(); 432 } 433 434 /** 435 * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the 436 * currently opened socket. 437 * <p> 438 * @param on True if Nagle's algorithm is to be enabled, false if not. 439 * @exception SocketException If the operation fails. 440 */ 441 public void setTcpNoDelay(boolean on) throws SocketException 442 { 443 _socket_.setTcpNoDelay(on); 444 } 445 446 447 /** 448 * Returns true if Nagle's algorithm is enabled on the currently opened 449 * socket. 450 * <p> 451 * @return True if Nagle's algorithm is enabled on the currently opened 452 * socket, false otherwise. 453 * @exception SocketException If the operation fails. 454 */ 455 public boolean getTcpNoDelay() throws SocketException 456 { 457 return _socket_.getTcpNoDelay(); 458 } 459 460 /** 461 * Sets the SO_KEEPALIVE flag on the currently opened socket. 462 * 463 * From the Javadocs, the default keepalive time is 2 hours (although this is 464 * implementation dependent). It looks as though the Windows WSA sockets implementation 465 * allows a specific keepalive value to be set, although this seems not to be the case on 466 * other systems. 467 * @param keepAlive If true, keepAlive is turned on 468 * @throws SocketException 469 * @since 2.2 470 */ 471 public void setKeepAlive(boolean keepAlive) throws SocketException { 472 _socket_.setKeepAlive(keepAlive); 473 } 474 475 /** 476 * Returns the current value of the SO_KEEPALIVE flag on the currently opened socket. 477 * 478 * @return True if SO_KEEPALIVE is enabled. 479 * @throws SocketException 480 * @since 2.2 481 */ 482 public boolean getKeepAlive() throws SocketException { 483 return _socket_.getKeepAlive(); 484 } 485 486 /** 487 * Sets the SO_LINGER timeout on the currently opened socket. 488 * <p> 489 * @param on True if linger is to be enabled, false if not. 490 * @param val The linger timeout (in hundredths of a second?) 491 * @exception SocketException If the operation fails. 492 */ 493 public void setSoLinger(boolean on, int val) throws SocketException 494 { 495 _socket_.setSoLinger(on, val); 496 } 497 498 499 /** 500 * Returns the current SO_LINGER timeout of the currently opened socket. 501 * <p> 502 * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns 503 * -1. 504 * @exception SocketException If the operation fails. 505 */ 506 public int getSoLinger() throws SocketException 507 { 508 return _socket_.getSoLinger(); 509 } 510 511 512 /** 513 * Returns the port number of the open socket on the local host used 514 * for the connection. 515 * <p> 516 * @return The port number of the open socket on the local host used 517 * for the connection. 518 */ 519 public int getLocalPort() 520 { 521 return _socket_.getLocalPort(); 522 } 523 524 525 /** 526 * Returns the local address to which the client's socket is bound. 527 * <p> 528 * @return The local address to which the client's socket is bound. 529 */ 530 public InetAddress getLocalAddress() 531 { 532 return _socket_.getLocalAddress(); 533 } 534 535 /** 536 * Returns the port number of the remote host to which the client is 537 * connected. 538 * <p> 539 * @return The port number of the remote host to which the client is 540 * connected. 541 */ 542 public int getRemotePort() 543 { 544 return _socket_.getPort(); 545 } 546 547 548 /** 549 * @return The remote address to which the client is connected. 550 */ 551 public InetAddress getRemoteAddress() 552 { 553 return _socket_.getInetAddress(); 554 } 555 556 557 /** 558 * Verifies that the remote end of the given socket is connected to the 559 * the same host that the SocketClient is currently connected to. This 560 * is useful for doing a quick security check when a client needs to 561 * accept a connection from a server, such as an FTP data connection or 562 * a BSD R command standard error stream. 563 * <p> 564 * @return True if the remote hosts are the same, false if not. 565 */ 566 public boolean verifyRemote(Socket socket) 567 { 568 InetAddress host1, host2; 569 570 host1 = socket.getInetAddress(); 571 host2 = getRemoteAddress(); 572 573 return host1.equals(host2); 574 } 575 576 577 /** 578 * Sets the SocketFactory used by the SocketClient to open socket 579 * connections. If the factory value is null, then a default 580 * factory is used (only do this to reset the factory after having 581 * previously altered it). 582 * <p> 583 * @param factory The new SocketFactory the SocketClient should use. 584 */ 585 public void setSocketFactory(SocketFactory factory) 586 { 587 if (factory == null) 588 _socketFactory_ = __DEFAULT_SOCKET_FACTORY; 589 else 590 _socketFactory_ = factory; 591 } 592 593 /** 594 * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket 595 * connections. If the factory value is null, then a default 596 * factory is used (only do this to reset the factory after having 597 * previously altered it). 598 * <p> 599 * @param factory The new ServerSocketFactory the SocketClient should use. 600 * @since 2.0 601 */ 602 public void setServerSocketFactory(ServerSocketFactory factory) { 603 if (factory == null) 604 _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; 605 else 606 _serverSocketFactory_ = factory; 607 } 608 609 /** 610 * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's 611 * connect() method. 612 * @param connectTimeout The connection timeout to use (in ms) 613 * @since 2.0 614 */ 615 public void setConnectTimeout(int connectTimeout) { 616 this.connectTimeout = connectTimeout; 617 } 618 619 /** 620 * Get the underlying socket connection timeout. 621 * @return timeout (in ms) 622 * @since 2.0 623 */ 624 public int getConnectTimeout() { 625 return connectTimeout; 626 } 627 628 /** 629 * Get the underlying {@link ServerSocketFactory} 630 * @return The server socket factory 631 * @since 2.2 632 */ 633 public ServerSocketFactory getServerSocketFactory() { 634 return _serverSocketFactory_; 635 } 636 637 } 638 639