1
2
3
4
5
6
7
8
9
10
11
12
13
14
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