View Javadoc

1   /*
2    * Copyright 2001-2005 The Apache Software Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.net;
17  
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.io.OutputStream;
21  import java.net.InetAddress;
22  import java.net.Socket;
23  import java.net.SocketException;
24  
25  /**
26   * The SocketClient provides the basic operations that are required of
27   * client objects accessing sockets.  It is meant to be
28   * subclassed to avoid having to rewrite the same code over and over again
29   * to open a socket, close a socket, set timeouts, etc.  Of special note
30   * is the {@link #setSocketFactory  setSocketFactory }
31   * method, which allows you to control the type of Socket the SocketClient
32   * creates for initiating network connections.  This is especially useful
33   * for adding SSL or proxy support as well as better support for applets.  For
34   * example, you could create a
35   * {@link org.apache.commons.net.SocketFactory} that
36   * requests browser security capabilities before creating a socket.
37   * All classes derived from SocketClient should use the
38   * {@link #_socketFactory_  _socketFactory_ } member variable to
39   * create Socket and ServerSocket instances rather than instanting
40   * them by directly invoking a constructor.  By honoring this contract
41   * you guarantee that a user will always be able to provide his own
42   * Socket implementations by substituting his own SocketFactory.
43   * @author Daniel F. Savarese
44   * @see SocketFactory
45   */
46  public abstract class SocketClient
47  {
48      /**
49       * The end of line character sequence used by most IETF protocols.  That
50       * is a carriage return followed by a newline: "\r\n"
51       */
52      public static final String NETASCII_EOL = "\r\n";
53  
54      /** The default SocketFactory shared by all SocketClient instances. */
55      private static final SocketFactory __DEFAULT_SOCKET_FACTORY =
56          new DefaultSocketFactory();
57  
58      /** The timeout to use after opening a socket. */
59      protected int _timeout_;
60  
61      /** The socket used for the connection. */
62      protected Socket _socket_;
63  
64      /**
65       * A status variable indicating if the client's socket is currently open.
66       */
67      protected boolean _isConnected_;
68  
69      /** The default port the client should connect to. */
70      protected int _defaultPort_;
71  
72      /** The socket's InputStream. */
73      protected InputStream _input_;
74  
75      /** The socket's OutputStream. */
76      protected OutputStream _output_;
77  
78      /** The socket's SocketFactory. */
79      protected SocketFactory _socketFactory_;
80  
81  
82      /**
83       * Default constructor for SocketClient.  Initializes
84       * _socket_ to null, _timeout_ to 0, _defaultPort to 0,
85       * _isConnected_ to false, and _socketFactory_ to a shared instance of
86       * {@link org.apache.commons.net.DefaultSocketFactory}.
87       */
88      public SocketClient()
89      {
90          _socket_ = null;
91          _input_ = null;
92          _output_ = null;
93          _timeout_ = 0;
94          _defaultPort_ = 0;
95          _isConnected_ = false;
96          _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
97      }
98  
99  
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