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