OSDN Git Service

2005-12-27 Tom Tromey <tromey@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / net / Socket.java
1 /* Socket.java -- Client socket implementation
2    Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Classpath.
6
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38
39 package java.net;
40
41 import gnu.java.net.PlainSocketImpl;
42
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.io.OutputStream;
46 import java.nio.channels.IllegalBlockingModeException;
47 import java.nio.channels.SocketChannel;
48
49
50 /* Written using on-line Java Platform 1.2 API Specification.
51  * Status:  I believe all methods are implemented.
52  */
53
54 /**
55  * This class models a client site socket.  A socket is a TCP/IP endpoint
56  * for network communications conceptually similar to a file handle.
57  * <p>
58  * This class does not actually do any work.  Instead, it redirects all of
59  * its calls to a socket implementation object which implements the
60  * <code>SocketImpl</code> interface.  The implementation class is
61  * instantiated by factory class that implements the
62  * <code>SocketImplFactory interface</code>.  A default
63  * factory is provided, however the factory may be set by a call to
64  * the <code>setSocketImplFactory</code> method.  Note that this may only be
65  * done once per virtual machine.  If a subsequent attempt is made to set the
66  * factory, a <code>SocketException</code> will be thrown.
67  *
68  * @author Aaron M. Renn (arenn@urbanophile.com)
69  * @author Per Bothner (bothner@cygnus.com)
70  */
71 public class Socket
72 {
73   /**
74    * This is the user SocketImplFactory for this class.  If this variable is
75    * null, a default factory is used.
76    */
77   static SocketImplFactory factory;
78
79   /**
80    * The implementation object to which calls are redirected
81    */
82   // package-private because ServerSocket.implAccept() needs to access it.
83   SocketImpl impl;
84
85   /**
86    * True if socket implementation was created by calling their
87    * create() method.
88    */
89   // package-private because ServerSocket.implAccept() needs to access it.
90   boolean implCreated;
91
92   /**
93    * True if the socket is bound.
94    * Package private so it can be set from ServerSocket when accept is called.
95    */
96   boolean bound;
97
98   /**
99    * True if input is shutdown.
100    */
101   private boolean inputShutdown;
102
103   /**
104    * True if output is shutdown.
105    */
106   private boolean outputShutdown;
107
108   /**
109    * Initializes a new instance of <code>Socket</code> object without
110    * connecting to a remote host.  This useful for subclasses of socket that
111    * might want this behavior.
112    *
113    * @specnote This constructor is public since JDK 1.4
114    * @since 1.1
115    */
116   public Socket()
117   {
118     if (factory != null)
119       impl = factory.createSocketImpl();
120     else
121       impl = new PlainSocketImpl();
122   }
123
124   /**
125    * Initializes a new instance of <code>Socket</code> object without
126    * connecting to a remote host.  This is useful for subclasses of socket
127    * that might want this behavior.
128    * <p>
129    * Additionally, this socket will be created using the supplied
130    * implementation class instead the default class or one returned by a
131    * factory.  If this value is <code>null</code>, the default Socket
132    * implementation is used.
133    *
134    * @param impl The <code>SocketImpl</code> to use for this
135    *             <code>Socket</code>
136    *
137    * @exception SocketException If an error occurs
138    *
139    * @since 1.1
140    */
141   protected Socket(SocketImpl impl) throws SocketException
142   {
143     if (impl == null)
144       this.impl = new PlainSocketImpl();
145     else
146       this.impl = impl;
147   }
148
149   /**
150    * Initializes a new instance of <code>Socket</code> and connects to the
151    * hostname and port specified as arguments.
152    *
153    * @param host The name of the host to connect to
154    * @param port The port number to connect to
155    *
156    * @exception UnknownHostException If the hostname cannot be resolved to a
157    * network address.
158    * @exception IOException If an error occurs
159    * @exception SecurityException If a security manager exists and its
160    * checkConnect method doesn't allow the operation
161    */
162   public Socket(String host, int port)
163     throws UnknownHostException, IOException
164   {
165     this(InetAddress.getByName(host), port, null, 0, true);
166   }
167
168   /**
169    * Initializes a new instance of <code>Socket</code> and connects to the
170    * address and port number specified as arguments.
171    *
172    * @param address The address to connect to
173    * @param port The port number to connect to
174    *
175    * @exception IOException If an error occurs
176    * @exception SecurityException If a security manager exists and its
177    * checkConnect method doesn't allow the operation
178    */
179   public Socket(InetAddress address, int port) throws IOException
180   {
181     this(address, port, null, 0, true);
182   }
183
184   /**
185    * Initializes a new instance of <code>Socket</code> that connects to the
186    * named host on the specified port and binds to the specified local address
187    * and port.
188    *
189    * @param host The name of the remote host to connect to.
190    * @param port The remote port to connect to.
191    * @param localAddr The local address to bind to.
192    * @param localPort The local port to bind to.
193    *
194    * @exception SecurityException If the <code>SecurityManager</code>
195    * exists and does not allow a connection to the specified host/port or
196    * binding to the specified local host/port.
197    * @exception IOException If a connection error occurs.
198    *
199    * @since 1.1
200    */
201   public Socket(String host, int port, InetAddress localAddr, int localPort)
202     throws IOException
203   {
204     this(InetAddress.getByName(host), port, localAddr, localPort, true);
205   }
206
207   /**
208    * Initializes a new instance of <code>Socket</code> and connects to the
209    * address and port number specified as arguments, plus binds to the
210    * specified local address and port.
211    *
212    * @param address The remote address to connect to
213    * @param port The remote port to connect to
214    * @param localAddr The local address to connect to
215    * @param localPort The local port to connect to
216    *
217    * @exception IOException If an error occurs
218    * @exception SecurityException If a security manager exists and its
219    * checkConnect method doesn't allow the operation
220    *
221    * @since 1.1
222    */
223   public Socket(InetAddress address, int port, InetAddress localAddr,
224                 int localPort) throws IOException
225   {
226     this(address, port, localAddr, localPort, true);
227   }
228
229   /**
230    * Initializes a new instance of <code>Socket</code> and connects to the
231    * hostname and port specified as arguments.  If the stream argument is set
232    * to <code>true</code>, then a stream socket is created.  If it is
233    * <code>false</code>, a datagram socket is created.
234    *
235    * @param host The name of the host to connect to
236    * @param port The port to connect to
237    * @param stream <code>true</code> for a stream socket, <code>false</code>
238    * for a datagram socket
239    *
240    * @exception IOException If an error occurs
241    * @exception SecurityException If a security manager exists and its
242    * checkConnect method doesn't allow the operation
243    *
244    * @deprecated Use the <code>DatagramSocket</code> class to create
245    * datagram oriented sockets.
246    */
247   public Socket(String host, int port, boolean stream)
248     throws IOException
249   {
250     this(InetAddress.getByName(host), port, null, 0, stream);
251   }
252
253   /**
254    * Initializes a new instance of <code>Socket</code> and connects to the
255    * address and port number specified as arguments.  If the stream param is
256    * <code>true</code>, a stream socket will be created, otherwise a datagram
257    * socket is created.
258    *
259    * @param host The address to connect to
260    * @param port The port number to connect to
261    * @param stream <code>true</code> to create a stream socket,
262    * <code>false</code> to create a datagram socket.
263    *
264    * @exception IOException If an error occurs
265    * @exception SecurityException If a security manager exists and its
266    * checkConnect method doesn't allow the operation
267    *
268    * @deprecated Use the <code>DatagramSocket</code> class to create
269    * datagram oriented sockets.
270    */
271   public Socket(InetAddress host, int port, boolean stream)
272     throws IOException
273   {
274     this(host, port, null, 0, stream);
275   }
276
277   /**
278    * This constructor is where the real work takes place.  Connect to the
279    * specified address and port.  Use default local values if not specified,
280    * otherwise use the local host and port passed in.  Create as stream or
281    * datagram based on "stream" argument.
282    * <p>
283    *
284    * @param raddr The remote address to connect to
285    * @param rport The remote port to connect to
286    * @param laddr The local address to connect to
287    * @param lport The local port to connect to
288    * @param stream true for a stream socket, false for a datagram socket
289    *
290    * @exception IOException If an error occurs
291    * @exception SecurityException If a security manager exists and its
292    * checkConnect method doesn't allow the operation
293    */
294   private Socket(InetAddress raddr, int rport, InetAddress laddr, int lport,
295                  boolean stream) throws IOException
296   {
297     this();
298
299     SecurityManager sm = System.getSecurityManager();
300     if (sm != null)
301       sm.checkConnect(raddr.getHostName(), rport);
302
303     // bind socket
304     SocketAddress bindaddr =
305       laddr == null ? null : new InetSocketAddress(laddr, lport);
306     bind(bindaddr);
307
308     // connect socket
309     connect(new InetSocketAddress(raddr, rport));
310
311     // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port,
312     // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as
313     // that default.  JDK 1.2 doc infers not to do a bind.
314   }
315
316   private SocketImpl getImpl() throws SocketException
317   {
318     try
319       {
320         if (! implCreated)
321           {
322             impl.create(true);
323             implCreated = true;
324           }
325       }
326     catch (IOException e)
327       {
328         SocketException se = new SocketException(e.toString());
329         se.initCause(e);
330         throw se;
331       }
332
333     return impl;
334   }
335
336   /**
337    * Binds the socket to the givent local address/port
338    *
339    * @param bindpoint The address/port to bind to
340    *
341    * @exception IOException If an error occurs
342    * @exception SecurityException If a security manager exists and its
343    * checkConnect method doesn't allow the operation
344    * @exception IllegalArgumentException If the address type is not supported
345    *
346    * @since 1.4
347    */
348   public void bind(SocketAddress bindpoint) throws IOException
349   {
350     if (isClosed())
351       throw new SocketException("socket is closed");
352
353     // XXX: JDK 1.4.1 API documentation says that if bindpoint is null the
354     // socket will be bound to an ephemeral port and a valid local address.
355     if (bindpoint == null)
356       bindpoint = new InetSocketAddress(InetAddress.ANY_IF, 0);
357
358     if (! (bindpoint instanceof InetSocketAddress))
359       throw new IllegalArgumentException();
360
361     InetSocketAddress tmp = (InetSocketAddress) bindpoint;
362
363     // bind to address/port
364     try
365       {
366         getImpl().bind(tmp.getAddress(), tmp.getPort());
367         bound = true;
368       }
369     catch (IOException exception)
370       {
371         close();
372         throw exception;
373       }
374     catch (RuntimeException exception)
375       {
376         close();
377         throw exception;
378       }
379     catch (Error error)
380       {
381         close();
382         throw error;
383       }
384   }
385
386   /**
387    * Connects the socket with a remote address.
388    *
389    * @param endpoint The address to connect to
390    *
391    * @exception IOException If an error occurs
392    * @exception IllegalArgumentException If the addess type is not supported
393    * @exception IllegalBlockingModeException If this socket has an associated
394    * channel, and the channel is in non-blocking mode
395    *
396    * @since 1.4
397    */
398   public void connect(SocketAddress endpoint) throws IOException
399   {
400     connect(endpoint, 0);
401   }
402
403   /**
404    * Connects the socket with a remote address. A timeout of zero is
405    * interpreted as an infinite timeout. The connection will then block
406    * until established or an error occurs.
407    *
408    * @param endpoint The address to connect to
409    * @param timeout The length of the timeout in milliseconds, or
410    * 0 to indicate no timeout.
411    *
412    * @exception IOException If an error occurs
413    * @exception IllegalArgumentException If the address type is not supported
414    * @exception IllegalBlockingModeException If this socket has an associated
415    * channel, and the channel is in non-blocking mode
416    * @exception SocketTimeoutException If the timeout is reached
417    *
418    * @since 1.4
419    */
420   public void connect(SocketAddress endpoint, int timeout)
421     throws IOException
422   {
423     if (isClosed())
424       throw new SocketException("socket is closed");
425
426     if (! (endpoint instanceof InetSocketAddress))
427       throw new IllegalArgumentException("unsupported address type");
428
429     // The Sun spec says that if we have an associated channel and
430     // it is in non-blocking mode, we throw an IllegalBlockingModeException.
431     // However, in our implementation if the channel itself initiated this
432     // operation, then we must honor it regardless of its blocking mode.
433     if (getChannel() != null && ! getChannel().isBlocking()
434         && ! ((PlainSocketImpl) getImpl()).isInChannelOperation())
435       throw new IllegalBlockingModeException();
436
437     if (! isBound())
438       bind(null);
439
440     getImpl().connect(endpoint, timeout);
441   }
442
443   /**
444    * Returns the address of the remote end of the socket.  If this socket
445    * is not connected, then <code>null</code> is returned.
446    *
447    * @return The remote address this socket is connected to
448    */
449   public InetAddress getInetAddress()
450   {
451     if (! isConnected())
452       return null;
453
454     try
455       {
456         return getImpl().getInetAddress();
457       }
458     catch (SocketException e)
459       {
460         // This cannot happen as we are connected.
461       }
462
463     return null;
464   }
465
466   /**
467    * Returns the local address to which this socket is bound.  If this socket
468    * is not connected, then a wildcard address, for which
469    * @see InetAddress#isAnyLocalAddress() is <code>true</code>, is returned.
470    *
471    * @return The local address
472    *
473    * @since 1.1
474    */
475   public InetAddress getLocalAddress()
476   {
477     if (! isBound())
478       return InetAddress.ANY_IF;
479
480     InetAddress addr = null;
481
482     try
483       {
484         addr = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
485       }
486     catch (SocketException e)
487       {
488         // (hopefully) shouldn't happen
489         // throw new java.lang.InternalError
490         //      ("Error in PlainSocketImpl.getOption");
491         return null;
492       }
493
494     // FIXME: According to libgcj, checkConnect() is supposed to be called
495     // before performing this operation.  Problems: 1) We don't have the
496     // addr until after we do it, so we do a post check.  2). The docs I
497     // see don't require this in the Socket case, only DatagramSocket, but
498     // we'll assume they mean both.
499     SecurityManager sm = System.getSecurityManager();
500     if (sm != null)
501       sm.checkConnect(addr.getHostName(), getLocalPort());
502
503     return addr;
504   }
505
506   /**
507    * Returns the port number of the remote end of the socket connection.  If
508    * this socket is not connected, then 0 is returned.
509    *
510    * @return The remote port this socket is connected to
511    */
512   public int getPort()
513   {
514     if (! isConnected())
515       return 0;
516
517     try
518       {
519         return getImpl().getPort();
520       }
521     catch (SocketException e)
522       {
523         // This cannot happen as we are connected.
524       }
525
526     return 0;
527   }
528
529   /**
530    * Returns the local port number to which this socket is bound.  If this
531    * socket is not connected, then -1 is returned.
532    *
533    * @return The local port
534    */
535   public int getLocalPort()
536   {
537     if (! isBound())
538       return -1;
539
540     try
541       {
542         if (getImpl() != null)
543           return getImpl().getLocalPort();
544       }
545     catch (SocketException e)
546       {
547         // This cannot happen as we are bound.
548       }
549
550     return -1;
551   }
552
553   /**
554    * Returns local socket address.
555    *
556    * @return the local socket address, null if not bound
557    *
558    * @since 1.4
559    */
560   public SocketAddress getLocalSocketAddress()
561   {
562     if (! isBound())
563       return null;
564
565     InetAddress addr = getLocalAddress();
566
567     try
568       {
569         return new InetSocketAddress(addr, getImpl().getLocalPort());
570       }
571     catch (SocketException e)
572       {
573         // This cannot happen as we are bound.
574         return null;
575       }
576   }
577
578   /**
579    * Returns the remote socket address.
580    *
581    * @return the remote socket address, null of not connected
582    *
583    * @since 1.4
584    */
585   public SocketAddress getRemoteSocketAddress()
586   {
587     if (! isConnected())
588       return null;
589
590     try
591       {
592         return new InetSocketAddress(getImpl().getInetAddress(),
593                                      getImpl().getPort());
594       }
595     catch (SocketException e)
596       {
597         // This cannot happen as we are connected.
598         return null;
599       }
600   }
601
602   /**
603    * Returns an InputStream for reading from this socket.
604    *
605    * @return The InputStream object
606    *
607    * @exception IOException If an error occurs or Socket is not connected
608    */
609   public InputStream getInputStream() throws IOException
610   {
611     if (isClosed())
612       throw new SocketException("socket is closed");
613
614     if (! isConnected())
615       throw new IOException("not connected");
616
617     return getImpl().getInputStream();
618   }
619
620   /**
621    * Returns an OutputStream for writing to this socket.
622    *
623    * @return The OutputStream object
624    *
625    * @exception IOException If an error occurs or Socket is not connected
626    */
627   public OutputStream getOutputStream() throws IOException
628   {
629     if (isClosed())
630       throw new SocketException("socket is closed");
631
632     if (! isConnected())
633       throw new IOException("not connected");
634
635     return getImpl().getOutputStream();
636   }
637
638   /**
639    * Sets the TCP_NODELAY option on the socket.
640    *
641    * @param on true to enable, false to disable
642    *
643    * @exception SocketException If an error occurs or Socket is not connected
644    *
645    * @since 1.1
646    */
647   public void setTcpNoDelay(boolean on) throws SocketException
648   {
649     if (isClosed())
650       throw new SocketException("socket is closed");
651
652     getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
653   }
654
655   /**
656    * Tests whether or not the TCP_NODELAY option is set on the socket.
657    * Returns true if enabled, false if disabled. When on it disables the
658    * Nagle algorithm which means that packets are always send immediatly and
659    * never merged together to reduce network trafic.
660    *
661    * @return Whether or not TCP_NODELAY is set
662    *
663    * @exception SocketException If an error occurs or Socket not connected
664    *
665    * @since 1.1
666    */
667   public boolean getTcpNoDelay() throws SocketException
668   {
669     if (isClosed())
670       throw new SocketException("socket is closed");
671
672     Object on = getImpl().getOption(SocketOptions.TCP_NODELAY);
673
674     if (on instanceof Boolean)
675       return (((Boolean) on).booleanValue());
676     else
677       throw new SocketException("Internal Error");
678   }
679
680   /**
681    * Sets the value of the SO_LINGER option on the socket.  If the
682    * SO_LINGER option is set on a socket and there is still data waiting to
683    * be sent when the socket is closed, then the close operation will block
684    * until either that data is delivered or until the timeout period
685    * expires.  The linger interval is specified in hundreths of a second
686    * (platform specific?)
687    *
688    * @param on true to enable SO_LINGER, false to disable
689    * @param linger The SO_LINGER timeout in hundreths of a second or -1 if
690    * SO_LINGER not set.
691    *
692    * @exception SocketException If an error occurs or Socket not connected
693    * @exception IllegalArgumentException If linger is negative
694    *
695    * @since 1.1
696    */
697   public void setSoLinger(boolean on, int linger) throws SocketException
698   {
699     if (isClosed())
700       throw new SocketException("socket is closed");
701
702     if (on)
703       {
704         if (linger < 0)
705           throw new IllegalArgumentException("SO_LINGER must be >= 0");
706
707         if (linger > 65535)
708           linger = 65535;
709
710         getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
711       }
712     else
713       getImpl().setOption(SocketOptions.SO_LINGER, Boolean.valueOf(false));
714   }
715
716   /**
717    * Returns the value of the SO_LINGER option on the socket.  If the
718    * SO_LINGER option is set on a socket and there is still data waiting to
719    * be sent when the socket is closed, then the close operation will block
720    * until either that data is delivered or until the timeout period
721    * expires.  This method either returns the timeouts (in hundredths of
722    * of a second (platform specific?)) if SO_LINGER is set, or -1 if
723    * SO_LINGER is not set.
724    *
725    * @return The SO_LINGER timeout in hundreths of a second or -1
726    * if SO_LINGER not set
727    *
728    * @exception SocketException If an error occurs or Socket is not connected
729    *
730    * @since 1.1
731    */
732   public int getSoLinger() throws SocketException
733   {
734     if (isClosed())
735       throw new SocketException("socket is closed");
736
737     Object linger = getImpl().getOption(SocketOptions.SO_LINGER);
738
739     if (linger instanceof Integer)
740       return (((Integer) linger).intValue());
741     else
742       return -1;
743   }
744
745   /**
746    * Sends urgent data through the socket
747    *
748    * @param data The data to send.
749    * Only the lowest eight bits of data are sent
750    *
751    * @exception IOException If an error occurs
752    *
753    * @since 1.4
754    */
755   public void sendUrgentData(int data) throws IOException
756   {
757     if (isClosed())
758       throw new SocketException("socket is closed");
759
760     getImpl().sendUrgentData(data);
761   }
762
763   /**
764    * Enables/disables the SO_OOBINLINE option
765    *
766    * @param on True if SO_OOBLINE should be enabled
767    *
768    * @exception SocketException If an error occurs
769    *
770    * @since 1.4
771    */
772   public void setOOBInline(boolean on) throws SocketException
773   {
774     if (isClosed())
775       throw new SocketException("socket is closed");
776
777     getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on));
778   }
779
780   /**
781    * Returns the current setting of the SO_OOBINLINE option for this socket
782    *
783    * @return True if SO_OOBINLINE is set, false otherwise.
784    *
785    * @exception SocketException If an error occurs
786    *
787    * @since 1.4
788    */
789   public boolean getOOBInline() throws SocketException
790   {
791     if (isClosed())
792       throw new SocketException("socket is closed");
793
794     Object buf = getImpl().getOption(SocketOptions.SO_OOBINLINE);
795
796     if (buf instanceof Boolean)
797       return (((Boolean) buf).booleanValue());
798     else
799       throw new SocketException("Internal Error: Unexpected type");
800   }
801
802   /**
803    * Sets the value of the SO_TIMEOUT option on the socket.  If this value
804    * is set, and an read/write is performed that does not complete within
805    * the timeout period, a short count is returned (or an EWOULDBLOCK signal
806    * would be sent in Unix if no data had been read).  A value of 0 for
807    * this option implies that there is no timeout (ie, operations will
808    * block forever).  On systems that have separate read and write timeout
809    * values, this method returns the read timeout.  This
810    * value is in milliseconds.
811    *
812    * @param timeout The length of the timeout in milliseconds, or
813    * 0 to indicate no timeout.
814    *
815    * @exception SocketException If an error occurs or Socket not connected
816    *
817    * @since 1.1
818    */
819   public synchronized void setSoTimeout(int timeout) throws SocketException
820   {
821     if (isClosed())
822       throw new SocketException("socket is closed");
823
824     if (timeout < 0)
825       throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0");
826
827     getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
828   }
829
830   /**
831    * Returns the value of the SO_TIMEOUT option on the socket.  If this value
832    * is set, and an read/write is performed that does not complete within
833    * the timeout period, a short count is returned (or an EWOULDBLOCK signal
834    * would be sent in Unix if no data had been read).  A value of 0 for
835    * this option implies that there is no timeout (ie, operations will
836    * block forever).  On systems that have separate read and write timeout
837    * values, this method returns the read timeout.  This
838    * value is in thousandths of a second (implementation specific?).
839    *
840    * @return The length of the timeout in thousandth's of a second or 0
841    * if not set
842    *
843    * @exception SocketException If an error occurs or Socket not connected
844    *
845    * @since 1.1
846    */
847   public synchronized int getSoTimeout() throws SocketException
848   {
849     if (isClosed())
850       throw new SocketException("socket is closed");
851
852     Object timeout = getImpl().getOption(SocketOptions.SO_TIMEOUT);
853     if (timeout instanceof Integer)
854       return (((Integer) timeout).intValue());
855     else
856       return 0;
857   }
858
859   /**
860    * This method sets the value for the system level socket option
861    * SO_SNDBUF to the specified value.  Note that valid values for this
862    * option are specific to a given operating system.
863    *
864    * @param size The new send buffer size.
865    *
866    * @exception SocketException If an error occurs or Socket not connected
867    * @exception IllegalArgumentException If size is 0 or negative
868    *
869    * @since 1.2
870    */
871   public void setSendBufferSize(int size) throws SocketException
872   {
873     if (isClosed())
874       throw new SocketException("socket is closed");
875
876     if (size <= 0)
877       throw new IllegalArgumentException("SO_SNDBUF value must be > 0");
878
879     getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
880   }
881
882   /**
883    * This method returns the value of the system level socket option
884    * SO_SNDBUF, which is used by the operating system to tune buffer
885    * sizes for data transfers.
886    *
887    * @return The send buffer size.
888    *
889    * @exception SocketException If an error occurs or socket not connected
890    *
891    * @since 1.2
892    */
893   public int getSendBufferSize() throws SocketException
894   {
895     if (isClosed())
896       throw new SocketException("socket is closed");
897
898     Object buf = getImpl().getOption(SocketOptions.SO_SNDBUF);
899
900     if (buf instanceof Integer)
901       return (((Integer) buf).intValue());
902     else
903       throw new SocketException("Internal Error: Unexpected type");
904   }
905
906   /**
907    * This method sets the value for the system level socket option
908    * SO_RCVBUF to the specified value.  Note that valid values for this
909    * option are specific to a given operating system.
910    *
911    * @param size The new receive buffer size.
912    *
913    * @exception SocketException If an error occurs or Socket is not connected
914    * @exception IllegalArgumentException If size is 0 or negative
915    *
916    * @since 1.2
917    */
918   public void setReceiveBufferSize(int size) throws SocketException
919   {
920     if (isClosed())
921       throw new SocketException("socket is closed");
922
923     if (size <= 0)
924       throw new IllegalArgumentException("SO_RCVBUF value must be > 0");
925
926     getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
927   }
928
929   /**
930    * This method returns the value of the system level socket option
931    * SO_RCVBUF, which is used by the operating system to tune buffer
932    * sizes for data transfers.
933    *
934    * @return The receive buffer size.
935    *
936    * @exception SocketException If an error occurs or Socket is not connected
937    *
938    * @since 1.2
939    */
940   public int getReceiveBufferSize() throws SocketException
941   {
942     if (isClosed())
943       throw new SocketException("socket is closed");
944
945     Object buf = getImpl().getOption(SocketOptions.SO_RCVBUF);
946
947     if (buf instanceof Integer)
948       return (((Integer) buf).intValue());
949     else
950       throw new SocketException("Internal Error: Unexpected type");
951   }
952
953   /**
954    * This method sets the value for the socket level socket option
955    * SO_KEEPALIVE.
956    *
957    * @param on True if SO_KEEPALIVE should be enabled
958    *
959    * @exception SocketException If an error occurs or Socket is not connected
960    *
961    * @since 1.3
962    */
963   public void setKeepAlive(boolean on) throws SocketException
964   {
965     if (isClosed())
966       throw new SocketException("socket is closed");
967
968     getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on));
969   }
970
971   /**
972    * This method returns the value of the socket level socket option
973    * SO_KEEPALIVE.
974    *
975    * @return The setting
976    *
977    * @exception SocketException If an error occurs or Socket is not connected
978    *
979    * @since 1.3
980    */
981   public boolean getKeepAlive() throws SocketException
982   {
983     if (isClosed())
984       throw new SocketException("socket is closed");
985
986     Object buf = getImpl().getOption(SocketOptions.SO_KEEPALIVE);
987
988     if (buf instanceof Boolean)
989       return (((Boolean) buf).booleanValue());
990     else
991       throw new SocketException("Internal Error: Unexpected type");
992   }
993
994   /**
995    * Closes the socket.
996    *
997    * @exception IOException If an error occurs
998    */
999   public synchronized void close() throws IOException
1000   {
1001     if (isClosed())
1002       return;
1003
1004     getImpl().close();
1005     impl = null;
1006     bound = false;
1007
1008     if (getChannel() != null)
1009       getChannel().close();
1010   }
1011
1012   /**
1013    * Converts this <code>Socket</code> to a <code>String</code>.
1014    *
1015    * @return The <code>String</code> representation of this <code>Socket</code>
1016    */
1017   public String toString()
1018   {
1019     try
1020       {
1021         if (isConnected())
1022           return ("Socket[addr=" + getImpl().getInetAddress() + ",port="
1023                  + getImpl().getPort() + ",localport="
1024                  + getImpl().getLocalPort() + "]");
1025       }
1026     catch (SocketException e)
1027       {
1028         // This cannot happen as we are connected.
1029       }
1030
1031     return "Socket[unconnected]";
1032   }
1033
1034   /**
1035    * Sets the <code>SocketImplFactory</code>.  This may be done only once per
1036    * virtual machine.  Subsequent attempts will generate a
1037    * <code>SocketException</code>.  Note that a <code>SecurityManager</code>
1038    * check is made prior to setting the factory.  If
1039    * insufficient privileges exist to set the factory, then an
1040    * <code>IOException</code> will be thrown.
1041    *
1042    * @param fac the factory to set
1043    *
1044    * @exception SecurityException If the <code>SecurityManager</code> does
1045    * not allow this operation.
1046    * @exception SocketException If the SocketImplFactory is already defined
1047    * @exception IOException If any other error occurs
1048    */
1049   public static synchronized void setSocketImplFactory(SocketImplFactory fac)
1050     throws IOException
1051   {
1052     // See if already set
1053     if (factory != null)
1054       throw new SocketException("SocketImplFactory already defined");
1055
1056     // Check permissions
1057     SecurityManager sm = System.getSecurityManager();
1058     if (sm != null)
1059       sm.checkSetFactory();
1060
1061     if (fac == null)
1062       throw new SocketException("SocketImplFactory cannot be null");
1063
1064     factory = fac;
1065   }
1066
1067   /**
1068    * Closes the input side of the socket stream.
1069    *
1070    * @exception IOException If an error occurs.
1071    *
1072    * @since 1.3
1073    */
1074   public void shutdownInput() throws IOException
1075   {
1076     if (isClosed())
1077       throw new SocketException("socket is closed");
1078
1079     getImpl().shutdownInput();
1080     inputShutdown = true;
1081   }
1082
1083   /**
1084    * Closes the output side of the socket stream.
1085    *
1086    * @exception IOException If an error occurs.
1087    *
1088    * @since 1.3
1089    */
1090   public void shutdownOutput() throws IOException
1091   {
1092     if (isClosed())
1093       throw new SocketException("socket is closed");
1094
1095     getImpl().shutdownOutput();
1096     outputShutdown = true;
1097   }
1098
1099   /**
1100    * Returns the socket channel associated with this socket.
1101    *
1102    * @return the associated socket channel,
1103    * null if no associated channel exists
1104    *
1105    * @since 1.4
1106    */
1107   public SocketChannel getChannel()
1108   {
1109     return null;
1110   }
1111
1112   /**
1113    * Checks if the SO_REUSEADDR option is enabled
1114    *
1115    * @return True if SO_REUSEADDR is set, false otherwise.
1116    *
1117    * @exception SocketException If an error occurs
1118    *
1119    * @since 1.4
1120    */
1121   public boolean getReuseAddress() throws SocketException
1122   {
1123     if (isClosed())
1124       throw new SocketException("socket is closed");
1125
1126     Object reuseaddr = getImpl().getOption(SocketOptions.SO_REUSEADDR);
1127
1128     if (! (reuseaddr instanceof Boolean))
1129       throw new SocketException("Internal Error");
1130
1131     return ((Boolean) reuseaddr).booleanValue();
1132   }
1133
1134   /**
1135    * Enables/Disables the SO_REUSEADDR option
1136    *
1137    * @param reuseAddress true if SO_REUSEADDR should be enabled,
1138    * false otherwise
1139    *
1140    * @exception SocketException If an error occurs
1141    *
1142    * @since 1.4
1143    */
1144   public void setReuseAddress(boolean reuseAddress) throws SocketException
1145   {
1146     if (isClosed())
1147       throw new SocketException("socket is closed");
1148
1149     getImpl().setOption(SocketOptions.SO_REUSEADDR,
1150                         Boolean.valueOf(reuseAddress));
1151   }
1152
1153   /**
1154    * Returns the current traffic class
1155    *
1156    * @return The current traffic class.
1157    *
1158    * @exception SocketException If an error occurs
1159    *
1160    * @see Socket#setTrafficClass(int tc)
1161    *
1162    * @since 1.4
1163    */
1164   public int getTrafficClass() throws SocketException
1165   {
1166     if (isClosed())
1167       throw new SocketException("socket is closed");
1168
1169     Object obj = getImpl().getOption(SocketOptions.IP_TOS);
1170
1171     if (obj instanceof Integer)
1172       return ((Integer) obj).intValue();
1173     else
1174       throw new SocketException("Unexpected type");
1175   }
1176
1177   /**
1178    * Sets the traffic class value
1179    *
1180    * @param tc The traffic class
1181    *
1182    * @exception SocketException If an error occurs
1183    * @exception IllegalArgumentException If tc value is illegal
1184    *
1185    * @see Socket#getTrafficClass()
1186    *
1187    * @since 1.4
1188    */
1189   public void setTrafficClass(int tc) throws SocketException
1190   {
1191     if (isClosed())
1192       throw new SocketException("socket is closed");
1193
1194     if (tc < 0 || tc > 255)
1195       throw new IllegalArgumentException();
1196
1197     getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
1198   }
1199
1200   /**
1201    * Checks if the socket is connected
1202    *
1203    * @return True if socket is connected, false otherwise.
1204    *
1205    * @since 1.4
1206    */
1207   public boolean isConnected()
1208   {
1209     try
1210       {
1211         if (getImpl() == null)
1212           return false;
1213
1214         return getImpl().getInetAddress() != null;
1215       }
1216     catch (SocketException e)
1217       {
1218         return false;
1219       }
1220   }
1221
1222   /**
1223    * Checks if the socket is already bound.
1224    *
1225    * @return True if socket is bound, false otherwise.
1226    *
1227    * @since 1.4
1228    */
1229   public boolean isBound()
1230   {
1231     return bound;
1232   }
1233
1234   /**
1235    * Checks if the socket is closed.
1236    *
1237    * @return True if socket is closed, false otherwise.
1238    *
1239    * @since 1.4
1240    */
1241   public boolean isClosed()
1242   {
1243     return impl == null;
1244   }
1245
1246   /**
1247    * Checks if the socket's input stream is shutdown
1248    *
1249    * @return True if input is shut down.
1250    *
1251    * @since 1.4
1252    */
1253   public boolean isInputShutdown()
1254   {
1255     return inputShutdown;
1256   }
1257
1258   /**
1259    * Checks if the socket's output stream is shutdown
1260    *
1261    * @return True if output is shut down.
1262    *
1263    * @since 1.4
1264    */
1265   public boolean isOutputShutdown()
1266   {
1267     return outputShutdown;
1268   }
1269 }