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