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