| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.net; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.InetAddress; |
| import java.net.Socket; |
| import java.net.SocketException; |
| import java.net.UnknownHostException; |
| |
| /** |
| * The SocketClient provides the basic operations that are required of |
| * client objects accessing sockets. It is meant to be |
| * subclassed to avoid having to rewrite the same code over and over again |
| * to open a socket, close a socket, set timeouts, etc. Of special note |
| * is the {@link #setSocketFactory setSocketFactory } |
| * method, which allows you to control the type of Socket the SocketClient |
| * creates for initiating network connections. This is especially useful |
| * for adding SSL or proxy support as well as better support for applets. For |
| * example, you could create a |
| * {@link org.apache.commons.net.SocketFactory} that |
| * requests browser security capabilities before creating a socket. |
| * All classes derived from SocketClient should use the |
| * {@link #_socketFactory_ _socketFactory_ } member variable to |
| * create Socket and ServerSocket instances rather than instanting |
| * them by directly invoking a constructor. By honoring this contract |
| * you guarantee that a user will always be able to provide his own |
| * Socket implementations by substituting his own SocketFactory. |
| * @author Daniel F. Savarese |
| * @see SocketFactory |
| */ |
| public abstract class SocketClient |
| { |
| /** |
| * The end of line character sequence used by most IETF protocols. That |
| * is a carriage return followed by a newline: "\r\n" |
| */ |
| public static final String NETASCII_EOL = "\r\n"; |
| |
| /** The default SocketFactory shared by all SocketClient instances. */ |
| private static final SocketFactory __DEFAULT_SOCKET_FACTORY = |
| new DefaultSocketFactory(); |
| |
| /** The timeout to use after opening a socket. */ |
| protected int _timeout_; |
| |
| /** The socket used for the connection. */ |
| protected Socket _socket_; |
| |
| /** |
| * A status variable indicating if the client's socket is currently open. |
| */ |
| protected boolean _isConnected_; |
| |
| /** The default port the client should connect to. */ |
| protected int _defaultPort_; |
| |
| /** The socket's InputStream. */ |
| protected InputStream _input_; |
| |
| /** The socket's OutputStream. */ |
| protected OutputStream _output_; |
| |
| /** The socket's SocketFactory. */ |
| protected SocketFactory _socketFactory_; |
| |
| |
| /** |
| * Default constructor for SocketClient. Initializes |
| * _socket_ to null, _timeout_ to 0, _defaultPort to 0, |
| * _isConnected_ to false, and _socketFactory_ to a shared instance of |
| * {@link org.apache.commons.net.DefaultSocketFactory}. |
| */ |
| public SocketClient() |
| { |
| _socket_ = null; |
| _input_ = null; |
| _output_ = null; |
| _timeout_ = 0; |
| _defaultPort_ = 0; |
| _isConnected_ = false; |
| _socketFactory_ = __DEFAULT_SOCKET_FACTORY; |
| } |
| |
| |
| /** |
| * Because there are so many connect() methods, the _connectAction_() |
| * method is provided as a means of performing some action immediately |
| * after establishing a connection, rather than reimplementing all |
| * of the connect() methods. The last action performed by every |
| * connect() method after opening a socket is to call this method. |
| * <p> |
| * This method sets the timeout on the just opened socket to the default |
| * timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, |
| * sets _input_ and _output_ to the socket's InputStream and OutputStream |
| * respectively, and sets _isConnected_ to true. |
| * <p> |
| * Subclasses overriding this method should start by calling |
| * <code> super._connectAction_() </code> first to ensure the |
| * initialization of the aforementioned protected variables. |
| */ |
| protected void _connectAction_() throws IOException |
| { |
| _socket_.setSoTimeout(_timeout_); |
| _input_ = _socket_.getInputStream(); |
| _output_ = _socket_.getOutputStream(); |
| _isConnected_ = true; |
| } |
| |
| |
| /** |
| * Opens a Socket connected to a remote host at the specified port and |
| * originating from the current host at a system assigned port. |
| * Before returning, {@link #_connectAction_ _connectAction_() } |
| * is called to perform connection initialization actions. |
| * <p> |
| * @param host The remote host. |
| * @param port The port to connect to on the remote host. |
| * @exception SocketException If the socket timeout could not be set. |
| * @exception IOException If the socket could not be opened. In most |
| * cases you will only want to catch IOException since SocketException is |
| * derived from it. |
| */ |
| public void connect(InetAddress host, int port) |
| throws SocketException, IOException |
| { |
| _socket_ = _socketFactory_.createSocket(host, port); |
| _connectAction_(); |
| } |
| |
| /** |
| * Opens a Socket connected to a remote host at the specified port and |
| * originating from the current host at a system assigned port. |
| * Before returning, {@link #_connectAction_ _connectAction_() } |
| * is called to perform connection initialization actions. |
| * <p> |
| * @param hostname The name of the remote host. |
| * @param port The port to connect to on the remote host. |
| * @exception SocketException If the socket timeout could not be set. |
| * @exception IOException If the socket could not be opened. In most |
| * cases you will only want to catch IOException since SocketException is |
| * derived from it. |
| * @exception UnknownHostException If the hostname cannot be resolved. |
| */ |
| public void connect(String hostname, int port) |
| throws SocketException, IOException, UnknownHostException |
| { |
| _socket_ = _socketFactory_.createSocket(hostname, port); |
| _connectAction_(); |
| } |
| |
| |
| /** |
| * Opens a Socket connected to a remote host at the specified port and |
| * originating from the specified local address and port. |
| * Before returning, {@link #_connectAction_ _connectAction_() } |
| * is called to perform connection initialization actions. |
| * <p> |
| * @param host The remote host. |
| * @param port The port to connect to on the remote host. |
| * @param localAddr The local address to use. |
| * @param localPort The local port to use. |
| * @exception SocketException If the socket timeout could not be set. |
| * @exception IOException If the socket could not be opened. In most |
| * cases you will only want to catch IOException since SocketException is |
| * derived from it. |
| */ |
| public void connect(InetAddress host, int port, |
| InetAddress localAddr, int localPort) |
| throws SocketException, IOException |
| { |
| _socket_ = _socketFactory_.createSocket(host, port, localAddr, localPort); |
| _connectAction_(); |
| } |
| |
| |
| /** |
| * Opens a Socket connected to a remote host at the specified port and |
| * originating from the specified local address and port. |
| * Before returning, {@link #_connectAction_ _connectAction_() } |
| * is called to perform connection initialization actions. |
| * <p> |
| * @param hostname The name of the remote host. |
| * @param port The port to connect to on the remote host. |
| * @param localAddr The local address to use. |
| * @param localPort The local port to use. |
| * @exception SocketException If the socket timeout could not be set. |
| * @exception IOException If the socket could not be opened. In most |
| * cases you will only want to catch IOException since SocketException is |
| * derived from it. |
| * @exception UnknownHostException If the hostname cannot be resolved. |
| */ |
| public void connect(String hostname, int port, |
| InetAddress localAddr, int localPort) |
| throws SocketException, IOException |
| { |
| _socket_ = |
| _socketFactory_.createSocket(hostname, port, localAddr, localPort); |
| _connectAction_(); |
| } |
| |
| |
| /** |
| * Opens a Socket connected to a remote host at the current default port |
| * and originating from the current host at a system assigned port. |
| * Before returning, {@link #_connectAction_ _connectAction_() } |
| * is called to perform connection initialization actions. |
| * <p> |
| * @param host The remote host. |
| * @exception SocketException If the socket timeout could not be set. |
| * @exception IOException If the socket could not be opened. In most |
| * cases you will only want to catch IOException since SocketException is |
| * derived from it. |
| */ |
| public void connect(InetAddress host) throws SocketException, IOException |
| { |
| connect(host, _defaultPort_); |
| } |
| |
| |
| /** |
| * Opens a Socket connected to a remote host at the current default |
| * port and originating from the current host at a system assigned port. |
| * Before returning, {@link #_connectAction_ _connectAction_() } |
| * is called to perform connection initialization actions. |
| * <p> |
| * @param hostname The name of the remote host. |
| * @exception SocketException If the socket timeout could not be set. |
| * @exception IOException If the socket could not be opened. In most |
| * cases you will only want to catch IOException since SocketException is |
| * derived from it. |
| * @exception UnknownHostException If the hostname cannot be resolved. |
| */ |
| public void connect(String hostname) throws SocketException, IOException |
| { |
| connect(hostname, _defaultPort_); |
| } |
| |
| |
| /** |
| * Disconnects the socket connection. |
| * You should call this method after you've finished using the class |
| * instance and also before you call |
| * {@link #connect connect() } |
| * again. _isConnected_ is set to false, _socket_ is set to null, |
| * _input_ is set to null, and _output_ is set to null. |
| * <p> |
| * @exception IOException If there is an error closing the socket. |
| */ |
| public void disconnect() throws IOException |
| { |
| if(_socket_ != null) _socket_.close(); |
| if(_input_ != null) _input_.close(); |
| if(_output_ != null) _output_.close(); |
| _socket_ = null; |
| _input_ = null; |
| _output_ = null; |
| _isConnected_ = false; |
| } |
| |
| |
| /** |
| * Returns true if the client is currently connected to a server. |
| * <p> |
| * @return True if the client is currently connected to a server, |
| * false otherwise. |
| */ |
| public boolean isConnected() |
| { |
| return _isConnected_; |
| } |
| |
| |
| /** |
| * Sets the default port the SocketClient should connect to when a port |
| * is not specified. The {@link #_defaultPort_ _defaultPort_ } |
| * variable stores this value. If never set, the default port is equal |
| * to zero. |
| * <p> |
| * @param port The default port to set. |
| */ |
| public void setDefaultPort(int port) |
| { |
| _defaultPort_ = port; |
| } |
| |
| /** |
| * Returns the current value of the default port (stored in |
| * {@link #_defaultPort_ _defaultPort_ }). |
| * <p> |
| * @return The current value of the default port. |
| */ |
| public int getDefaultPort() |
| { |
| return _defaultPort_; |
| } |
| |
| |
| /** |
| * Set the default timeout in milliseconds to use when opening a socket. |
| * This value is only used previous to a call to |
| * {@link #connect connect()} |
| * and should not be confused with {@link #setSoTimeout setSoTimeout()} |
| * which operates on an the currently opened socket. _timeout_ contains |
| * the new timeout value. |
| * <p> |
| * @param timeout The timeout in milliseconds to use for the socket |
| * connection. |
| */ |
| public void setDefaultTimeout(int timeout) |
| { |
| _timeout_ = timeout; |
| } |
| |
| |
| /** |
| * Returns the default timeout in milliseconds that is used when |
| * opening a socket. |
| * <p> |
| * @return The default timeout in milliseconds that is used when |
| * opening a socket. |
| */ |
| public int getDefaultTimeout() |
| { |
| return _timeout_; |
| } |
| |
| |
| /** |
| * Set the timeout in milliseconds of a currently open connection. |
| * Only call this method after a connection has been opened |
| * by {@link #connect connect()}. |
| * <p> |
| * @param timeout The timeout in milliseconds to use for the currently |
| * open socket connection. |
| * @exception SocketException If the operation fails. |
| */ |
| public void setSoTimeout(int timeout) throws SocketException |
| { |
| _socket_.setSoTimeout(timeout); |
| } |
| |
| |
| /** |
| * Returns the timeout in milliseconds of the currently opened socket. |
| * <p> |
| * @return The timeout in milliseconds of the currently opened socket. |
| * @exception SocketException If the operation fails. |
| */ |
| public int getSoTimeout() throws SocketException |
| { |
| return _socket_.getSoTimeout(); |
| } |
| |
| /** |
| * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the |
| * currently opened socket. |
| * <p> |
| * @param on True if Nagle's algorithm is to be enabled, false if not. |
| * @exception SocketException If the operation fails. |
| */ |
| public void setTcpNoDelay(boolean on) throws SocketException |
| { |
| _socket_.setTcpNoDelay(on); |
| } |
| |
| |
| /** |
| * Returns true if Nagle's algorithm is enabled on the currently opened |
| * socket. |
| * <p> |
| * @return True if Nagle's algorithm is enabled on the currently opened |
| * socket, false otherwise. |
| * @exception SocketException If the operation fails. |
| */ |
| public boolean getTcpNoDelay() throws SocketException |
| { |
| return _socket_.getTcpNoDelay(); |
| } |
| |
| |
| /** |
| * Sets the SO_LINGER timeout on the currently opened socket. |
| * <p> |
| * @param on True if linger is to be enabled, false if not. |
| * @param val The linger timeout (in hundredths of a second?) |
| * @exception SocketException If the operation fails. |
| */ |
| public void setSoLinger(boolean on, int val) throws SocketException |
| { |
| _socket_.setSoLinger(on, val); |
| } |
| |
| |
| /** |
| * Returns the current SO_LINGER timeout of the currently opened socket. |
| * <p> |
| * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns |
| * -1. |
| * @exception SocketException If the operation fails. |
| */ |
| public int getSoLinger() throws SocketException |
| { |
| return _socket_.getSoLinger(); |
| } |
| |
| |
| /** |
| * Returns the port number of the open socket on the local host used |
| * for the connection. |
| * <p> |
| * @return The port number of the open socket on the local host used |
| * for the connection. |
| */ |
| public int getLocalPort() |
| { |
| return _socket_.getLocalPort(); |
| } |
| |
| |
| /** |
| * Returns the local address to which the client's socket is bound. |
| * <p> |
| * @return The local address to which the client's socket is bound. |
| */ |
| public InetAddress getLocalAddress() |
| { |
| return _socket_.getLocalAddress(); |
| } |
| |
| /** |
| * Returns the port number of the remote host to which the client is |
| * connected. |
| * <p> |
| * @return The port number of the remote host to which the client is |
| * connected. |
| */ |
| public int getRemotePort() |
| { |
| return _socket_.getPort(); |
| } |
| |
| |
| /** |
| * @return The remote address to which the client is connected. |
| */ |
| public InetAddress getRemoteAddress() |
| { |
| return _socket_.getInetAddress(); |
| } |
| |
| |
| /** |
| * Verifies that the remote end of the given socket is connected to the |
| * the same host that the SocketClient is currently connected to. This |
| * is useful for doing a quick security check when a client needs to |
| * accept a connection from a server, such as an FTP data connection or |
| * a BSD R command standard error stream. |
| * <p> |
| * @return True if the remote hosts are the same, false if not. |
| */ |
| public boolean verifyRemote(Socket socket) |
| { |
| InetAddress host1, host2; |
| |
| host1 = socket.getInetAddress(); |
| host2 = getRemoteAddress(); |
| |
| return host1.equals(host2); |
| } |
| |
| |
| /** |
| * Sets the SocketFactory used by the SocketClient to open socket |
| * connections. If the factory value is null, then a default |
| * factory is used (only do this to reset the factory after having |
| * previously altered it). |
| * <p> |
| * @param factory The new SocketFactory the SocketClient should use. |
| */ |
| public void setSocketFactory(SocketFactory factory) |
| { |
| if (factory == null) |
| _socketFactory_ = __DEFAULT_SOCKET_FACTORY; |
| else |
| _socketFactory_ = factory; |
| } |
| } |
| |
| |