1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.net.InetAddress;
24 import java.net.InetSocketAddress;
25 import java.net.Socket;
26 import java.net.SocketException;
27 import java.net.UnknownHostException;
28
29 import javax.net.ServerSocketFactory;
30 import javax.net.SocketFactory;
31
32
33 /**
34 * The SocketClient provides the basic operations that are required of
35 * client objects accessing sockets. It is meant to be
36 * subclassed to avoid having to rewrite the same code over and over again
37 * to open a socket, close a socket, set timeouts, etc. Of special note
38 * is the {@link #setSocketFactory setSocketFactory }
39 * method, which allows you to control the type of Socket the SocketClient
40 * creates for initiating network connections. This is especially useful
41 * for adding SSL or proxy support as well as better support for applets. For
42 * example, you could create a
43 * {@link org.apache.commons.net.SocketFactory} that
44 * requests browser security capabilities before creating a socket.
45 * All classes derived from SocketClient should use the
46 * {@link #_socketFactory_ _socketFactory_ } member variable to
47 * create Socket and ServerSocket instances rather than instanting
48 * them by directly invoking a constructor. By honoring this contract
49 * you guarantee that a user will always be able to provide his own
50 * Socket implementations by substituting his own SocketFactory.
51 * @author Daniel F. Savarese
52 * @see SocketFactory
53 */
54 public abstract class SocketClient
55 {
56 /**
57 * The end of line character sequence used by most IETF protocols. That
58 * is a carriage return followed by a newline: "\r\n"
59 */
60 public static final String NETASCII_EOL = "\r\n";
61
62 /** The default SocketFactory shared by all SocketClient instances. */
63 private static final SocketFactory __DEFAULT_SOCKET_FACTORY =
64 SocketFactory.getDefault();
65
66 private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY =
67 ServerSocketFactory.getDefault();
68
69 /** The timeout to use after opening a socket. */
70 protected int _timeout_;
71
72 /** The socket used for the connection. */
73 protected Socket _socket_;
74
75 /** The default port the client should connect to. */
76 protected int _defaultPort_;
77
78 /** The socket's InputStream. */
79 protected InputStream _input_;
80
81 /** The socket's OutputStream. */
82 protected OutputStream _output_;
83
84 /** The socket's SocketFactory. */
85 protected SocketFactory _socketFactory_;
86
87 /** The socket's ServerSocket Factory. */
88 protected ServerSocketFactory _serverSocketFactory_;
89
90 /** The socket's connect timeout (0 = infinite timeout) */
91 private static final int DEFAULT_CONNECT_TIMEOUT = 0;
92 protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
93
94 /**
95 * Default constructor for SocketClient. Initializes
96 * _socket_ to null, _timeout_ to 0, _defaultPort to 0,
97 * _isConnected_ to false, and _socketFactory_ to a shared instance of
98 * {@link org.apache.commons.net.DefaultSocketFactory}.
99 */
100 public SocketClient()
101 {
102 _socket_ = null;
103 _input_ = null;
104 _output_ = null;
105 _timeout_ = 0;
106 _defaultPort_ = 0;
107 _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
108 _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY;
109 }
110
111
112 /**
113 * Because there are so many connect() methods, the _connectAction_()
114 * method is provided as a means of performing some action immediately
115 * after establishing a connection, rather than reimplementing all
116 * of the connect() methods. The last action performed by every
117 * connect() method after opening a socket is to call this method.
118 * <p>
119 * This method sets the timeout on the just opened socket to the default
120 * timeout set by {@link #setDefaultTimeout setDefaultTimeout() },
121 * sets _input_ and _output_ to the socket's InputStream and OutputStream
122 * respectively, and sets _isConnected_ to true.
123 * <p>
124 * Subclasses overriding this method should start by calling
125 * <code> super._connectAction_() </code> first to ensure the
126 * initialization of the aforementioned protected variables.
127 */
128 protected void _connectAction_() throws IOException
129 {
130 _socket_.setSoTimeout(_timeout_);
131 _input_ = _socket_.getInputStream();
132 _output_ = _socket_.getOutputStream();
133 }
134
135
136 /**
137 * Opens a Socket connected to a remote host at the specified port and
138 * originating from the current host at a system assigned port.
139 * Before returning, {@link #_connectAction_ _connectAction_() }
140 * is called to perform connection initialization actions.
141 * <p>
142 * @param host The remote host.
143 * @param port The port to connect to on the remote host.
144 * @exception SocketException If the socket timeout could not be set.
145 * @exception IOException If the socket could not be opened. In most
146 * cases you will only want to catch IOException since SocketException is
147 * derived from it.
148 */
149 public void connect(InetAddress host, int port)
150 throws SocketException, IOException
151 {
152 _socket_ = _socketFactory_.createSocket();
153 _socket_.connect(new InetSocketAddress(host, port), connectTimeout);
154
155 _connectAction_();
156 }
157
158 /**
159 * Opens a Socket connected to a remote host at the specified port and
160 * originating from the current host at a system assigned port.
161 * Before returning, {@link #_connectAction_ _connectAction_() }
162 * is called to perform connection initialization actions.
163 * <p>
164 * @param hostname The name of the remote host.
165 * @param port The port to connect to on the remote host.
166 * @exception SocketException If the socket timeout could not be set.
167 * @exception IOException If the socket could not be opened. In most
168 * cases you will only want to catch IOException since SocketException is
169 * derived from it.
170 * @exception UnknownHostException If the hostname cannot be resolved.
171 */
172 public void connect(String hostname, int port)
173 throws SocketException, IOException
174 {
175 _socket_= _socketFactory_.createSocket();
176 _socket_.connect(new InetSocketAddress(hostname, port), connectTimeout);
177
178 _connectAction_();
179 }
180
181
182 /**
183 * Opens a Socket connected to a remote host at the specified port and
184 * originating from the specified local address and port.
185 * Before returning, {@link #_connectAction_ _connectAction_() }
186 * is called to perform connection initialization actions.
187 * <p>
188 * @param host The remote host.
189 * @param port The port to connect to on the remote host.
190 * @param localAddr The local address to use.
191 * @param localPort The local port to use.
192 * @exception SocketException If the socket timeout could not be set.
193 * @exception IOException If the socket could not be opened. In most
194 * cases you will only want to catch IOException since SocketException is
195 * derived from it.
196 */
197 public void connect(InetAddress host, int port,
198 InetAddress localAddr, int localPort)
199 throws SocketException, IOException
200 {
201 _socket_ = _socketFactory_.createSocket();
202 _socket_.bind(new InetSocketAddress(localAddr, localPort));
203 _socket_.connect(new InetSocketAddress(host, port), connectTimeout);
204
205 _connectAction_();
206 }
207
208
209 /**
210 * Opens a Socket connected to a remote host at the specified port and
211 * originating from the specified local address and port.
212 * Before returning, {@link #_connectAction_ _connectAction_() }
213 * is called to perform connection initialization actions.
214 * <p>
215 * @param hostname The name of the remote host.
216 * @param port The port to connect to on the remote host.
217 * @param localAddr The local address to use.
218 * @param localPort The local port to use.
219 * @exception SocketException If the socket timeout could not be set.
220 * @exception IOException If the socket could not be opened. In most
221 * cases you will only want to catch IOException since SocketException is
222 * derived from it.
223 * @exception UnknownHostException If the hostname cannot be resolved.
224 */
225 public void connect(String hostname, int port,
226 InetAddress localAddr, int localPort)
227 throws SocketException, IOException
228 {
229 _socket_ =
230 _socketFactory_.createSocket(hostname, port, localAddr, localPort);
231 _connectAction_();
232 }
233
234
235 /**
236 * Opens a Socket connected to a remote host at the current default port
237 * 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 host 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 */
247 public void connect(InetAddress host) throws SocketException, IOException
248 {
249 connect(host, _defaultPort_);
250 }
251
252
253 /**
254 * Opens a Socket connected to a remote host at the current default
255 * port and originating from the current host at a system assigned port.
256 * Before returning, {@link #_connectAction_ _connectAction_() }
257 * is called to perform connection initialization actions.
258 * <p>
259 * @param hostname The name of the remote host.
260 * @exception SocketException If the socket timeout could not be set.
261 * @exception IOException If the socket could not be opened. In most
262 * cases you will only want to catch IOException since SocketException is
263 * derived from it.
264 * @exception UnknownHostException If the hostname cannot be resolved.
265 */
266 public void connect(String hostname) throws SocketException, IOException
267 {
268 connect(hostname, _defaultPort_);
269 }
270
271
272 /**
273 * Disconnects the socket connection.
274 * You should call this method after you've finished using the class
275 * instance and also before you call
276 * {@link #connect connect() }
277 * again. _isConnected_ is set to false, _socket_ is set to null,
278 * _input_ is set to null, and _output_ is set to null.
279 * <p>
280 * @exception IOException If there is an error closing the socket.
281 */
282 public void disconnect() throws IOException
283 {
284 if (_socket_ != null) _socket_.close();
285 if (_input_ != null) _input_.close();
286 if (_output_ != null) _output_.close();
287 if (_socket_ != null) _socket_ = null;
288 _input_ = null;
289 _output_ = null;
290 }
291
292
293 /**
294 * Returns true if the client is currently connected to a server.
295 * <p>
296 * @return True if the client is currently connected to a server,
297 * false otherwise.
298 */
299 public boolean isConnected()
300 {
301 if (_socket_ == null)
302 return false;
303
304 return _socket_.isConnected();
305 }
306
307
308 /**
309 * Sets the default port the SocketClient should connect to when a port
310 * is not specified. The {@link #_defaultPort_ _defaultPort_ }
311 * variable stores this value. If never set, the default port is equal
312 * to zero.
313 * <p>
314 * @param port The default port to set.
315 */
316 public void setDefaultPort(int port)
317 {
318 _defaultPort_ = port;
319 }
320
321 /**
322 * Returns the current value of the default port (stored in
323 * {@link #_defaultPort_ _defaultPort_ }).
324 * <p>
325 * @return The current value of the default port.
326 */
327 public int getDefaultPort()
328 {
329 return _defaultPort_;
330 }
331
332
333 /**
334 * Set the default timeout in milliseconds to use when opening a socket.
335 * This value is only used previous to a call to
336 * {@link #connect connect()}
337 * and should not be confused with {@link #setSoTimeout setSoTimeout()}
338 * which operates on an the currently opened socket. _timeout_ contains
339 * the new timeout value.
340 * <p>
341 * @param timeout The timeout in milliseconds to use for the socket
342 * connection.
343 */
344 public void setDefaultTimeout(int timeout)
345 {
346 _timeout_ = timeout;
347 }
348
349
350 /**
351 * Returns the default timeout in milliseconds that is used when
352 * opening a socket.
353 * <p>
354 * @return The default timeout in milliseconds that is used when
355 * opening a socket.
356 */
357 public int getDefaultTimeout()
358 {
359 return _timeout_;
360 }
361
362
363 /**
364 * Set the timeout in milliseconds of a currently open connection.
365 * Only call this method after a connection has been opened
366 * by {@link #connect connect()}.
367 * <p>
368 * @param timeout The timeout in milliseconds to use for the currently
369 * open socket connection.
370 * @exception SocketException If the operation fails.
371 */
372 public void setSoTimeout(int timeout) throws SocketException
373 {
374 _socket_.setSoTimeout(timeout);
375 }
376
377
378 /**
379 * Set the underlying socket send buffer size.
380 * <p>
381 * @param size The size of the buffer in bytes.
382 * @throws SocketException
383 * @since 2.0
384 */
385 public void setSendBufferSize(int size) throws SocketException {
386 _socket_.setSendBufferSize(size);
387 }
388
389
390 /**
391 * Sets the underlying socket receive buffer size.
392 * <p>
393 * @param size The size of the buffer in bytes.
394 * @throws SocketException
395 * @since 2.0
396 */
397 public void setReceiveBufferSize(int size) throws SocketException {
398 _socket_.setReceiveBufferSize(size);
399 }
400
401
402 /**
403 * Returns the timeout in milliseconds of the currently opened socket.
404 * <p>
405 * @return The timeout in milliseconds of the currently opened socket.
406 * @exception SocketException If the operation fails.
407 */
408 public int getSoTimeout() throws SocketException
409 {
410 return _socket_.getSoTimeout();
411 }
412
413 /**
414 * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the
415 * currently opened socket.
416 * <p>
417 * @param on True if Nagle's algorithm is to be enabled, false if not.
418 * @exception SocketException If the operation fails.
419 */
420 public void setTcpNoDelay(boolean on) throws SocketException
421 {
422 _socket_.setTcpNoDelay(on);
423 }
424
425
426 /**
427 * Returns true if Nagle's algorithm is enabled on the currently opened
428 * socket.
429 * <p>
430 * @return True if Nagle's algorithm is enabled on the currently opened
431 * socket, false otherwise.
432 * @exception SocketException If the operation fails.
433 */
434 public boolean getTcpNoDelay() throws SocketException
435 {
436 return _socket_.getTcpNoDelay();
437 }
438
439
440 /**
441 * Sets the SO_LINGER timeout on the currently opened socket.
442 * <p>
443 * @param on True if linger is to be enabled, false if not.
444 * @param val The linger timeout (in hundredths of a second?)
445 * @exception SocketException If the operation fails.
446 */
447 public void setSoLinger(boolean on, int val) throws SocketException
448 {
449 _socket_.setSoLinger(on, val);
450 }
451
452
453 /**
454 * Returns the current SO_LINGER timeout of the currently opened socket.
455 * <p>
456 * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns
457 * -1.
458 * @exception SocketException If the operation fails.
459 */
460 public int getSoLinger() throws SocketException
461 {
462 return _socket_.getSoLinger();
463 }
464
465
466 /**
467 * Returns the port number of the open socket on the local host used
468 * for the connection.
469 * <p>
470 * @return The port number of the open socket on the local host used
471 * for the connection.
472 */
473 public int getLocalPort()
474 {
475 return _socket_.getLocalPort();
476 }
477
478
479 /**
480 * Returns the local address to which the client's socket is bound.
481 * <p>
482 * @return The local address to which the client's socket is bound.
483 */
484 public InetAddress getLocalAddress()
485 {
486 return _socket_.getLocalAddress();
487 }
488
489 /**
490 * Returns the port number of the remote host to which the client is
491 * connected.
492 * <p>
493 * @return The port number of the remote host to which the client is
494 * connected.
495 */
496 public int getRemotePort()
497 {
498 return _socket_.getPort();
499 }
500
501
502 /**
503 * @return The remote address to which the client is connected.
504 */
505 public InetAddress getRemoteAddress()
506 {
507 return _socket_.getInetAddress();
508 }
509
510
511 /**
512 * Verifies that the remote end of the given socket is connected to the
513 * the same host that the SocketClient is currently connected to. This
514 * is useful for doing a quick security check when a client needs to
515 * accept a connection from a server, such as an FTP data connection or
516 * a BSD R command standard error stream.
517 * <p>
518 * @return True if the remote hosts are the same, false if not.
519 */
520 public boolean verifyRemote(Socket socket)
521 {
522 InetAddress host1, host2;
523
524 host1 = socket.getInetAddress();
525 host2 = getRemoteAddress();
526
527 return host1.equals(host2);
528 }
529
530
531 /**
532 * Sets the SocketFactory used by the SocketClient to open socket
533 * connections. If the factory value is null, then a default
534 * factory is used (only do this to reset the factory after having
535 * previously altered it).
536 * <p>
537 * @param factory The new SocketFactory the SocketClient should use.
538 */
539 public void setSocketFactory(SocketFactory factory)
540 {
541 if (factory == null)
542 _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
543 else
544 _socketFactory_ = factory;
545 }
546
547 /**
548 * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket
549 * connections. If the factory value is null, then a default
550 * factory is used (only do this to reset the factory after having
551 * previously altered it).
552 * <p>
553 * @param factory The new ServerSocketFactory the SocketClient should use.
554 * @since 2.0
555 */
556 public void setServerSocketFactory(ServerSocketFactory factory) {
557 if (factory == null)
558 _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY;
559 else
560 _serverSocketFactory_ = factory;
561 }
562
563 /**
564 * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's
565 * connect() method.
566 * @param connectTimeout The connection timeout to use (in ms)
567 * @since 2.0
568 */
569 public void setConnectTimeout(int connectTimeout) {
570 this.connectTimeout = connectTimeout;
571 }
572
573 /**
574 * Get the underlying socket connection timeout.
575 * @return
576 * @since 2.0
577 */
578 public int getConnectTimeout() {
579 return connectTimeout;
580 }
581
582
583
584 }
585
586