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