001 /* 002 * Copyright 2001-2005 The Apache Software Foundation 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.apache.commons.net; 017 018 import java.io.IOException; 019 import java.io.InputStream; 020 import java.io.OutputStream; 021 import java.net.InetAddress; 022 import java.net.Socket; 023 import java.net.SocketException; 024 025 /** 026 * The SocketClient provides the basic operations that are required of 027 * client objects accessing sockets. It is meant to be 028 * subclassed to avoid having to rewrite the same code over and over again 029 * to open a socket, close a socket, set timeouts, etc. Of special note 030 * is the {@link #setSocketFactory setSocketFactory } 031 * method, which allows you to control the type of Socket the SocketClient 032 * creates for initiating network connections. This is especially useful 033 * for adding SSL or proxy support as well as better support for applets. For 034 * example, you could create a 035 * {@link org.apache.commons.net.SocketFactory} that 036 * requests browser security capabilities before creating a socket. 037 * All classes derived from SocketClient should use the 038 * {@link #_socketFactory_ _socketFactory_ } member variable to 039 * create Socket and ServerSocket instances rather than instanting 040 * them by directly invoking a constructor. By honoring this contract 041 * you guarantee that a user will always be able to provide his own 042 * Socket implementations by substituting his own SocketFactory. 043 * @author Daniel F. Savarese 044 * @see SocketFactory 045 */ 046 public abstract class SocketClient 047 { 048 /** 049 * The end of line character sequence used by most IETF protocols. That 050 * is a carriage return followed by a newline: "\r\n" 051 */ 052 public static final String NETASCII_EOL = "\r\n"; 053 054 /** The default SocketFactory shared by all SocketClient instances. */ 055 private static final SocketFactory __DEFAULT_SOCKET_FACTORY = 056 new DefaultSocketFactory(); 057 058 /** The timeout to use after opening a socket. */ 059 protected int _timeout_; 060 061 /** The socket used for the connection. */ 062 protected Socket _socket_; 063 064 /** 065 * A status variable indicating if the client's socket is currently open. 066 */ 067 protected boolean _isConnected_; 068 069 /** The default port the client should connect to. */ 070 protected int _defaultPort_; 071 072 /** The socket's InputStream. */ 073 protected InputStream _input_; 074 075 /** The socket's OutputStream. */ 076 protected OutputStream _output_; 077 078 /** The socket's SocketFactory. */ 079 protected SocketFactory _socketFactory_; 080 081 082 /** 083 * Default constructor for SocketClient. Initializes 084 * _socket_ to null, _timeout_ to 0, _defaultPort to 0, 085 * _isConnected_ to false, and _socketFactory_ to a shared instance of 086 * {@link org.apache.commons.net.DefaultSocketFactory}. 087 */ 088 public SocketClient() 089 { 090 _socket_ = null; 091 _input_ = null; 092 _output_ = null; 093 _timeout_ = 0; 094 _defaultPort_ = 0; 095 _isConnected_ = false; 096 _socketFactory_ = __DEFAULT_SOCKET_FACTORY; 097 } 098 099 100 /** 101 * Because there are so many connect() methods, the _connectAction_() 102 * method is provided as a means of performing some action immediately 103 * after establishing a connection, rather than reimplementing all 104 * of the connect() methods. The last action performed by every 105 * connect() method after opening a socket is to call this method. 106 * <p> 107 * This method sets the timeout on the just opened socket to the default 108 * timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, 109 * sets _input_ and _output_ to the socket's InputStream and OutputStream 110 * respectively, and sets _isConnected_ to true. 111 * <p> 112 * Subclasses overriding this method should start by calling 113 * <code> super._connectAction_() </code> first to ensure the 114 * initialization of the aforementioned protected variables. 115 */ 116 protected void _connectAction_() throws IOException 117 { 118 _socket_.setSoTimeout(_timeout_); 119 _input_ = _socket_.getInputStream(); 120 _output_ = _socket_.getOutputStream(); 121 _isConnected_ = true; 122 } 123 124 125 /** 126 * Opens a Socket connected to a remote host at the specified port and 127 * originating from the current host at a system assigned port. 128 * Before returning, {@link #_connectAction_ _connectAction_() } 129 * is called to perform connection initialization actions. 130 * <p> 131 * @param host The remote host. 132 * @param port The port to connect to on the remote host. 133 * @exception SocketException If the socket timeout could not be set. 134 * @exception IOException If the socket could not be opened. In most 135 * cases you will only want to catch IOException since SocketException is 136 * derived from it. 137 */ 138 public void connect(InetAddress host, int port) 139 throws SocketException, IOException 140 { 141 _socket_ = _socketFactory_.createSocket(host, port); 142 _connectAction_(); 143 } 144 145 /** 146 * Opens a Socket connected to a remote host at the specified port and 147 * originating from the current host at a system assigned port. 148 * Before returning, {@link #_connectAction_ _connectAction_() } 149 * is called to perform connection initialization actions. 150 * <p> 151 * @param hostname The name of the remote host. 152 * @param port The port to connect to on the remote host. 153 * @exception SocketException If the socket timeout could not be set. 154 * @exception IOException If the socket could not be opened. In most 155 * cases you will only want to catch IOException since SocketException is 156 * derived from it. 157 * @exception UnknownHostException If the hostname cannot be resolved. 158 */ 159 public void connect(String hostname, int port) 160 throws SocketException, IOException 161 { 162 _socket_ = _socketFactory_.createSocket(hostname, port); 163 _connectAction_(); 164 } 165 166 167 /** 168 * Opens a Socket connected to a remote host at the specified port and 169 * originating from the specified local address and port. 170 * Before returning, {@link #_connectAction_ _connectAction_() } 171 * is called to perform connection initialization actions. 172 * <p> 173 * @param host The remote host. 174 * @param port The port to connect to on the remote host. 175 * @param localAddr The local address to use. 176 * @param localPort The local port to use. 177 * @exception SocketException If the socket timeout could not be set. 178 * @exception IOException If the socket could not be opened. In most 179 * cases you will only want to catch IOException since SocketException is 180 * derived from it. 181 */ 182 public void connect(InetAddress host, int port, 183 InetAddress localAddr, int localPort) 184 throws SocketException, IOException 185 { 186 _socket_ = _socketFactory_.createSocket(host, port, localAddr, localPort); 187 _connectAction_(); 188 } 189 190 191 /** 192 * Opens a Socket connected to a remote host at the specified port and 193 * originating from the specified local address and port. 194 * Before returning, {@link #_connectAction_ _connectAction_() } 195 * is called to perform connection initialization actions. 196 * <p> 197 * @param hostname The name of the remote host. 198 * @param port The port to connect to on the remote host. 199 * @param localAddr The local address to use. 200 * @param localPort The local port to use. 201 * @exception SocketException If the socket timeout could not be set. 202 * @exception IOException If the socket could not be opened. In most 203 * cases you will only want to catch IOException since SocketException is 204 * derived from it. 205 * @exception UnknownHostException If the hostname cannot be resolved. 206 */ 207 public void connect(String hostname, int port, 208 InetAddress localAddr, int localPort) 209 throws SocketException, IOException 210 { 211 _socket_ = 212 _socketFactory_.createSocket(hostname, port, localAddr, localPort); 213 _connectAction_(); 214 } 215 216 217 /** 218 * Opens a Socket connected to a remote host at the current default port 219 * and originating from the current host at a system assigned port. 220 * Before returning, {@link #_connectAction_ _connectAction_() } 221 * is called to perform connection initialization actions. 222 * <p> 223 * @param host The remote host. 224 * @exception SocketException If the socket timeout could not be set. 225 * @exception IOException If the socket could not be opened. In most 226 * cases you will only want to catch IOException since SocketException is 227 * derived from it. 228 */ 229 public void connect(InetAddress host) throws SocketException, IOException 230 { 231 connect(host, _defaultPort_); 232 } 233 234 235 /** 236 * Opens a Socket connected to a remote host at the current default 237 * port 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 hostname The name of 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 * @exception UnknownHostException If the hostname cannot be resolved. 247 */ 248 public void connect(String hostname) throws SocketException, IOException 249 { 250 connect(hostname, _defaultPort_); 251 } 252 253 254 /** 255 * Disconnects the socket connection. 256 * You should call this method after you've finished using the class 257 * instance and also before you call 258 * {@link #connect connect() } 259 * again. _isConnected_ is set to false, _socket_ is set to null, 260 * _input_ is set to null, and _output_ is set to null. 261 * <p> 262 * @exception IOException If there is an error closing the socket. 263 */ 264 public void disconnect() throws IOException 265 { 266 _socket_.close(); 267 _input_.close(); 268 _output_.close(); 269 _socket_ = null; 270 _input_ = null; 271 _output_ = null; 272 _isConnected_ = false; 273 } 274 275 276 /** 277 * Returns true if the client is currently connected to a server. 278 * <p> 279 * @return True if the client is currently connected to a server, 280 * false otherwise. 281 */ 282 public boolean isConnected() 283 { 284 return _isConnected_; 285 } 286 287 288 /** 289 * Sets the default port the SocketClient should connect to when a port 290 * is not specified. The {@link #_defaultPort_ _defaultPort_ } 291 * variable stores this value. If never set, the default port is equal 292 * to zero. 293 * <p> 294 * @param port The default port to set. 295 */ 296 public void setDefaultPort(int port) 297 { 298 _defaultPort_ = port; 299 } 300 301 /** 302 * Returns the current value of the default port (stored in 303 * {@link #_defaultPort_ _defaultPort_ }). 304 * <p> 305 * @return The current value of the default port. 306 */ 307 public int getDefaultPort() 308 { 309 return _defaultPort_; 310 } 311 312 313 /** 314 * Set the default timeout in milliseconds to use when opening a socket. 315 * This value is only used previous to a call to 316 * {@link #connect connect()} 317 * and should not be confused with {@link #setSoTimeout setSoTimeout()} 318 * which operates on an the currently opened socket. _timeout_ contains 319 * the new timeout value. 320 * <p> 321 * @param timeout The timeout in milliseconds to use for the socket 322 * connection. 323 */ 324 public void setDefaultTimeout(int timeout) 325 { 326 _timeout_ = timeout; 327 } 328 329 330 /** 331 * Returns the default timeout in milliseconds that is used when 332 * opening a socket. 333 * <p> 334 * @return The default timeout in milliseconds that is used when 335 * opening a socket. 336 */ 337 public int getDefaultTimeout() 338 { 339 return _timeout_; 340 } 341 342 343 /** 344 * Set the timeout in milliseconds of a currently open connection. 345 * Only call this method after a connection has been opened 346 * by {@link #connect connect()}. 347 * <p> 348 * @param timeout The timeout in milliseconds to use for the currently 349 * open socket connection. 350 * @exception SocketException If the operation fails. 351 */ 352 public void setSoTimeout(int timeout) throws SocketException 353 { 354 _socket_.setSoTimeout(timeout); 355 } 356 357 358 /** 359 * Returns the timeout in milliseconds of the currently opened socket. 360 * <p> 361 * @return The timeout in milliseconds of the currently opened socket. 362 * @exception SocketException If the operation fails. 363 */ 364 public int getSoTimeout() throws SocketException 365 { 366 return _socket_.getSoTimeout(); 367 } 368 369 /** 370 * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the 371 * currently opened socket. 372 * <p> 373 * @param on True if Nagle's algorithm is to be enabled, false if not. 374 * @exception SocketException If the operation fails. 375 */ 376 public void setTcpNoDelay(boolean on) throws SocketException 377 { 378 _socket_.setTcpNoDelay(on); 379 } 380 381 382 /** 383 * Returns true if Nagle's algorithm is enabled on the currently opened 384 * socket. 385 * <p> 386 * @return True if Nagle's algorithm is enabled on the currently opened 387 * socket, false otherwise. 388 * @exception SocketException If the operation fails. 389 */ 390 public boolean getTcpNoDelay() throws SocketException 391 { 392 return _socket_.getTcpNoDelay(); 393 } 394 395 396 /** 397 * Sets the SO_LINGER timeout on the currently opened socket. 398 * <p> 399 * @param on True if linger is to be enabled, false if not. 400 * @param val The linger timeout (in hundredths of a second?) 401 * @exception SocketException If the operation fails. 402 */ 403 public void setSoLinger(boolean on, int val) throws SocketException 404 { 405 _socket_.setSoLinger(on, val); 406 } 407 408 409 /** 410 * Returns the current SO_LINGER timeout of the currently opened socket. 411 * <p> 412 * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns 413 * -1. 414 * @exception SocketException If the operation fails. 415 */ 416 public int getSoLinger() throws SocketException 417 { 418 return _socket_.getSoLinger(); 419 } 420 421 422 /** 423 * Returns the port number of the open socket on the local host used 424 * for the connection. 425 * <p> 426 * @return The port number of the open socket on the local host used 427 * for the connection. 428 */ 429 public int getLocalPort() 430 { 431 return _socket_.getLocalPort(); 432 } 433 434 435 /** 436 * Returns the local address to which the client's socket is bound. 437 * <p> 438 * @return The local address to which the client's socket is bound. 439 */ 440 public InetAddress getLocalAddress() 441 { 442 return _socket_.getLocalAddress(); 443 } 444 445 /** 446 * Returns the port number of the remote host to which the client is 447 * connected. 448 * <p> 449 * @return The port number of the remote host to which the client is 450 * connected. 451 */ 452 public int getRemotePort() 453 { 454 return _socket_.getPort(); 455 } 456 457 458 /** 459 * @return The remote address to which the client is connected. 460 */ 461 public InetAddress getRemoteAddress() 462 { 463 return _socket_.getInetAddress(); 464 } 465 466 467 /** 468 * Verifies that the remote end of the given socket is connected to the 469 * the same host that the SocketClient is currently connected to. This 470 * is useful for doing a quick security check when a client needs to 471 * accept a connection from a server, such as an FTP data connection or 472 * a BSD R command standard error stream. 473 * <p> 474 * @return True if the remote hosts are the same, false if not. 475 */ 476 public boolean verifyRemote(Socket socket) 477 { 478 InetAddress host1, host2; 479 480 host1 = socket.getInetAddress(); 481 host2 = getRemoteAddress(); 482 483 return host1.equals(host2); 484 } 485 486 487 /** 488 * Sets the SocketFactory used by the SocketClient to open socket 489 * connections. If the factory value is null, then a default 490 * factory is used (only do this to reset the factory after having 491 * previously altered it). 492 * <p> 493 * @param factory The new SocketFactory the SocketClient should use. 494 */ 495 public void setSocketFactory(SocketFactory factory) 496 { 497 if (factory == null) 498 _socketFactory_ = __DEFAULT_SOCKET_FACTORY; 499 else 500 _socketFactory_ = factory; 501 } 502 } 503 504