OSDN Git Service

0ff6e6ea0321de9380687ec067602fbe6112b7af
[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     try
441       {
442         getImpl().connect(endpoint, timeout);
443       }
444     catch (IOException exception)
445       {
446         close();
447         throw exception;
448       }
449     catch (RuntimeException exception)
450       {
451         close();
452         throw exception;
453       }
454     catch (Error error)
455       {
456         close();
457         throw error;
458       }
459   }
460
461   /**
462    * Returns the address of the remote end of the socket.  If this socket
463    * is not connected, then <code>null</code> is returned.
464    *
465    * @return The remote address this socket is connected to
466    */
467   public InetAddress getInetAddress()
468   {
469     if (! isConnected())
470       return null;
471
472     try
473       {
474         return getImpl().getInetAddress();
475       }
476     catch (SocketException e)
477       {
478         // This cannot happen as we are connected.
479       }
480
481     return null;
482   }
483
484   /**
485    * Returns the local address to which this socket is bound.  If this socket
486    * is not connected, then a wildcard address, for which
487    * @see InetAddress#isAnyLocalAddress() is <code>true</code>, is returned.
488    *
489    * @return The local address
490    *
491    * @since 1.1
492    */
493   public InetAddress getLocalAddress()
494   {
495     if (! isBound())
496       return InetAddress.ANY_IF;
497
498     InetAddress addr = null;
499
500     try
501       {
502         addr = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
503       }
504     catch (SocketException e)
505       {
506         // (hopefully) shouldn't happen
507         // throw new java.lang.InternalError
508         //      ("Error in PlainSocketImpl.getOption");
509         return null;
510       }
511
512     // FIXME: According to libgcj, checkConnect() is supposed to be called
513     // before performing this operation.  Problems: 1) We don't have the
514     // addr until after we do it, so we do a post check.  2). The docs I
515     // see don't require this in the Socket case, only DatagramSocket, but
516     // we'll assume they mean both.
517     SecurityManager sm = System.getSecurityManager();
518     if (sm != null)
519       sm.checkConnect(addr.getHostName(), getLocalPort());
520
521     return addr;
522   }
523
524   /**
525    * Returns the port number of the remote end of the socket connection.  If
526    * this socket is not connected, then 0 is returned.
527    *
528    * @return The remote port this socket is connected to
529    */
530   public int getPort()
531   {
532     if (! isConnected())
533       return 0;
534
535     try
536       {
537         return getImpl().getPort();
538       }
539     catch (SocketException e)
540       {
541         // This cannot happen as we are connected.
542       }
543
544     return 0;
545   }
546
547   /**
548    * Returns the local port number to which this socket is bound.  If this
549    * socket is not connected, then -1 is returned.
550    *
551    * @return The local port
552    */
553   public int getLocalPort()
554   {
555     if (! isBound())
556       return -1;
557
558     try
559       {
560         if (getImpl() != null)
561           return getImpl().getLocalPort();
562       }
563     catch (SocketException e)
564       {
565         // This cannot happen as we are bound.
566       }
567
568     return -1;
569   }
570
571   /**
572    * Returns local socket address.
573    *
574    * @return the local socket address, null if not bound
575    *
576    * @since 1.4
577    */
578   public SocketAddress getLocalSocketAddress()
579   {
580     if (! isBound())
581       return null;
582
583     InetAddress addr = getLocalAddress();
584
585     try
586       {
587         return new InetSocketAddress(addr, getImpl().getLocalPort());
588       }
589     catch (SocketException e)
590       {
591         // This cannot happen as we are bound.
592         return null;
593       }
594   }
595
596   /**
597    * Returns the remote socket address.
598    *
599    * @return the remote socket address, null of not connected
600    *
601    * @since 1.4
602    */
603   public SocketAddress getRemoteSocketAddress()
604   {
605     if (! isConnected())
606       return null;
607
608     try
609       {
610         return new InetSocketAddress(getImpl().getInetAddress(),
611                                      getImpl().getPort());
612       }
613     catch (SocketException e)
614       {
615         // This cannot happen as we are connected.
616         return null;
617       }
618   }
619
620   /**
621    * Returns an InputStream for reading from this socket.
622    *
623    * @return The InputStream object
624    *
625    * @exception IOException If an error occurs or Socket is not connected
626    */
627   public InputStream getInputStream() 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().getInputStream();
636   }
637
638   /**
639    * Returns an OutputStream for writing to this socket.
640    *
641    * @return The OutputStream object
642    *
643    * @exception IOException If an error occurs or Socket is not connected
644    */
645   public OutputStream getOutputStream() throws IOException
646   {
647     if (isClosed())
648       throw new SocketException("socket is closed");
649
650     if (! isConnected())
651       throw new IOException("not connected");
652
653     return getImpl().getOutputStream();
654   }
655
656   /**
657    * Sets the TCP_NODELAY option on the socket.
658    *
659    * @param on true to enable, false to disable
660    *
661    * @exception SocketException If an error occurs or Socket is not connected
662    *
663    * @since 1.1
664    */
665   public void setTcpNoDelay(boolean on) throws SocketException
666   {
667     if (isClosed())
668       throw new SocketException("socket is closed");
669
670     getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
671   }
672
673   /**
674    * Tests whether or not the TCP_NODELAY option is set on the socket.
675    * Returns true if enabled, false if disabled. When on it disables the
676    * Nagle algorithm which means that packets are always send immediatly and
677    * never merged together to reduce network trafic.
678    *
679    * @return Whether or not TCP_NODELAY is set
680    *
681    * @exception SocketException If an error occurs or Socket not connected
682    *
683    * @since 1.1
684    */
685   public boolean getTcpNoDelay() throws SocketException
686   {
687     if (isClosed())
688       throw new SocketException("socket is closed");
689
690     Object on = getImpl().getOption(SocketOptions.TCP_NODELAY);
691
692     if (on instanceof Boolean)
693       return (((Boolean) on).booleanValue());
694     else
695       throw new SocketException("Internal Error");
696   }
697
698   /**
699    * Sets the value of the SO_LINGER option on the socket.  If the
700    * SO_LINGER option is set on a socket and there is still data waiting to
701    * be sent when the socket is closed, then the close operation will block
702    * until either that data is delivered or until the timeout period
703    * expires.  The linger interval is specified in hundreths of a second
704    * (platform specific?)
705    *
706    * @param on true to enable SO_LINGER, false to disable
707    * @param linger The SO_LINGER timeout in hundreths of a second or -1 if
708    * SO_LINGER not set.
709    *
710    * @exception SocketException If an error occurs or Socket not connected
711    * @exception IllegalArgumentException If linger is negative
712    *
713    * @since 1.1
714    */
715   public void setSoLinger(boolean on, int linger) throws SocketException
716   {
717     if (isClosed())
718       throw new SocketException("socket is closed");
719
720     if (on)
721       {
722         if (linger < 0)
723           throw new IllegalArgumentException("SO_LINGER must be >= 0");
724
725         if (linger > 65535)
726           linger = 65535;
727
728         getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
729       }
730     else
731       getImpl().setOption(SocketOptions.SO_LINGER, Boolean.valueOf(false));
732   }
733
734   /**
735    * Returns the value of the SO_LINGER option on the socket.  If the
736    * SO_LINGER option is set on a socket and there is still data waiting to
737    * be sent when the socket is closed, then the close operation will block
738    * until either that data is delivered or until the timeout period
739    * expires.  This method either returns the timeouts (in hundredths of
740    * of a second (platform specific?)) if SO_LINGER is set, or -1 if
741    * SO_LINGER is not set.
742    *
743    * @return The SO_LINGER timeout in hundreths of a second or -1
744    * if SO_LINGER not set
745    *
746    * @exception SocketException If an error occurs or Socket is not connected
747    *
748    * @since 1.1
749    */
750   public int getSoLinger() throws SocketException
751   {
752     if (isClosed())
753       throw new SocketException("socket is closed");
754
755     Object linger = getImpl().getOption(SocketOptions.SO_LINGER);
756
757     if (linger instanceof Integer)
758       return (((Integer) linger).intValue());
759     else
760       return -1;
761   }
762
763   /**
764    * Sends urgent data through the socket
765    *
766    * @param data The data to send.
767    * Only the lowest eight bits of data are sent
768    *
769    * @exception IOException If an error occurs
770    *
771    * @since 1.4
772    */
773   public void sendUrgentData(int data) throws IOException
774   {
775     if (isClosed())
776       throw new SocketException("socket is closed");
777
778     getImpl().sendUrgentData(data);
779   }
780
781   /**
782    * Enables/disables the SO_OOBINLINE option
783    *
784    * @param on True if SO_OOBLINE should be enabled
785    *
786    * @exception SocketException If an error occurs
787    *
788    * @since 1.4
789    */
790   public void setOOBInline(boolean on) throws SocketException
791   {
792     if (isClosed())
793       throw new SocketException("socket is closed");
794
795     getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on));
796   }
797
798   /**
799    * Returns the current setting of the SO_OOBINLINE option for this socket
800    *
801    * @return True if SO_OOBINLINE is set, false otherwise.
802    *
803    * @exception SocketException If an error occurs
804    *
805    * @since 1.4
806    */
807   public boolean getOOBInline() throws SocketException
808   {
809     if (isClosed())
810       throw new SocketException("socket is closed");
811
812     Object buf = getImpl().getOption(SocketOptions.SO_OOBINLINE);
813
814     if (buf instanceof Boolean)
815       return (((Boolean) buf).booleanValue());
816     else
817       throw new SocketException("Internal Error: Unexpected type");
818   }
819
820   /**
821    * Sets the value of the SO_TIMEOUT option on the socket.  If this value
822    * is set, and an read/write is performed that does not complete within
823    * the timeout period, a short count is returned (or an EWOULDBLOCK signal
824    * would be sent in Unix if no data had been read).  A value of 0 for
825    * this option implies that there is no timeout (ie, operations will
826    * block forever).  On systems that have separate read and write timeout
827    * values, this method returns the read timeout.  This
828    * value is in milliseconds.
829    *
830    * @param timeout The length of the timeout in milliseconds, or
831    * 0 to indicate no timeout.
832    *
833    * @exception SocketException If an error occurs or Socket not connected
834    *
835    * @since 1.1
836    */
837   public synchronized void setSoTimeout(int timeout) throws SocketException
838   {
839     if (isClosed())
840       throw new SocketException("socket is closed");
841
842     if (timeout < 0)
843       throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0");
844
845     getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
846   }
847
848   /**
849    * Returns the value of the SO_TIMEOUT option on the socket.  If this value
850    * is set, and an read/write is performed that does not complete within
851    * the timeout period, a short count is returned (or an EWOULDBLOCK signal
852    * would be sent in Unix if no data had been read).  A value of 0 for
853    * this option implies that there is no timeout (ie, operations will
854    * block forever).  On systems that have separate read and write timeout
855    * values, this method returns the read timeout.  This
856    * value is in thousandths of a second (implementation specific?).
857    *
858    * @return The length of the timeout in thousandth's of a second or 0
859    * if not set
860    *
861    * @exception SocketException If an error occurs or Socket not connected
862    *
863    * @since 1.1
864    */
865   public synchronized int getSoTimeout() throws SocketException
866   {
867     if (isClosed())
868       throw new SocketException("socket is closed");
869
870     Object timeout = getImpl().getOption(SocketOptions.SO_TIMEOUT);
871     if (timeout instanceof Integer)
872       return (((Integer) timeout).intValue());
873     else
874       return 0;
875   }
876
877   /**
878    * This method sets the value for the system level socket option
879    * SO_SNDBUF to the specified value.  Note that valid values for this
880    * option are specific to a given operating system.
881    *
882    * @param size The new send buffer size.
883    *
884    * @exception SocketException If an error occurs or Socket not connected
885    * @exception IllegalArgumentException If size is 0 or negative
886    *
887    * @since 1.2
888    */
889   public void setSendBufferSize(int size) throws SocketException
890   {
891     if (isClosed())
892       throw new SocketException("socket is closed");
893
894     if (size <= 0)
895       throw new IllegalArgumentException("SO_SNDBUF value must be > 0");
896
897     getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
898   }
899
900   /**
901    * This method returns the value of the system level socket option
902    * SO_SNDBUF, which is used by the operating system to tune buffer
903    * sizes for data transfers.
904    *
905    * @return The send buffer size.
906    *
907    * @exception SocketException If an error occurs or socket not connected
908    *
909    * @since 1.2
910    */
911   public int getSendBufferSize() throws SocketException
912   {
913     if (isClosed())
914       throw new SocketException("socket is closed");
915
916     Object buf = getImpl().getOption(SocketOptions.SO_SNDBUF);
917
918     if (buf instanceof Integer)
919       return (((Integer) buf).intValue());
920     else
921       throw new SocketException("Internal Error: Unexpected type");
922   }
923
924   /**
925    * This method sets the value for the system level socket option
926    * SO_RCVBUF to the specified value.  Note that valid values for this
927    * option are specific to a given operating system.
928    *
929    * @param size The new receive buffer size.
930    *
931    * @exception SocketException If an error occurs or Socket is not connected
932    * @exception IllegalArgumentException If size is 0 or negative
933    *
934    * @since 1.2
935    */
936   public void setReceiveBufferSize(int size) throws SocketException
937   {
938     if (isClosed())
939       throw new SocketException("socket is closed");
940
941     if (size <= 0)
942       throw new IllegalArgumentException("SO_RCVBUF value must be > 0");
943
944     getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
945   }
946
947   /**
948    * This method returns the value of the system level socket option
949    * SO_RCVBUF, which is used by the operating system to tune buffer
950    * sizes for data transfers.
951    *
952    * @return The receive buffer size.
953    *
954    * @exception SocketException If an error occurs or Socket is not connected
955    *
956    * @since 1.2
957    */
958   public int getReceiveBufferSize() throws SocketException
959   {
960     if (isClosed())
961       throw new SocketException("socket is closed");
962
963     Object buf = getImpl().getOption(SocketOptions.SO_RCVBUF);
964
965     if (buf instanceof Integer)
966       return (((Integer) buf).intValue());
967     else
968       throw new SocketException("Internal Error: Unexpected type");
969   }
970
971   /**
972    * This method sets the value for the socket level socket option
973    * SO_KEEPALIVE.
974    *
975    * @param on True if SO_KEEPALIVE should be enabled
976    *
977    * @exception SocketException If an error occurs or Socket is not connected
978    *
979    * @since 1.3
980    */
981   public void setKeepAlive(boolean on) throws SocketException
982   {
983     if (isClosed())
984       throw new SocketException("socket is closed");
985
986     getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on));
987   }
988
989   /**
990    * This method returns the value of the socket level socket option
991    * SO_KEEPALIVE.
992    *
993    * @return The setting
994    *
995    * @exception SocketException If an error occurs or Socket is not connected
996    *
997    * @since 1.3
998    */
999   public boolean getKeepAlive() throws SocketException
1000   {
1001     if (isClosed())
1002       throw new SocketException("socket is closed");
1003
1004     Object buf = getImpl().getOption(SocketOptions.SO_KEEPALIVE);
1005
1006     if (buf instanceof Boolean)
1007       return (((Boolean) buf).booleanValue());
1008     else
1009       throw new SocketException("Internal Error: Unexpected type");
1010   }
1011
1012   /**
1013    * Closes the socket.
1014    *
1015    * @exception IOException If an error occurs
1016    */
1017   public synchronized void close() throws IOException
1018   {
1019     if (isClosed())
1020       return;
1021
1022     getImpl().close();
1023     impl = null;
1024     bound = false;
1025
1026     if (getChannel() != null)
1027       getChannel().close();
1028   }
1029
1030   /**
1031    * Converts this <code>Socket</code> to a <code>String</code>.
1032    *
1033    * @return The <code>String</code> representation of this <code>Socket</code>
1034    */
1035   public String toString()
1036   {
1037     try
1038       {
1039         if (isConnected())
1040           return ("Socket[addr=" + getImpl().getInetAddress() + ",port="
1041                  + getImpl().getPort() + ",localport="
1042                  + getImpl().getLocalPort() + "]");
1043       }
1044     catch (SocketException e)
1045       {
1046         // This cannot happen as we are connected.
1047       }
1048
1049     return "Socket[unconnected]";
1050   }
1051
1052   /**
1053    * Sets the <code>SocketImplFactory</code>.  This may be done only once per
1054    * virtual machine.  Subsequent attempts will generate a
1055    * <code>SocketException</code>.  Note that a <code>SecurityManager</code>
1056    * check is made prior to setting the factory.  If
1057    * insufficient privileges exist to set the factory, then an
1058    * <code>IOException</code> will be thrown.
1059    *
1060    * @param fac the factory to set
1061    *
1062    * @exception SecurityException If the <code>SecurityManager</code> does
1063    * not allow this operation.
1064    * @exception SocketException If the SocketImplFactory is already defined
1065    * @exception IOException If any other error occurs
1066    */
1067   public static synchronized void setSocketImplFactory(SocketImplFactory fac)
1068     throws IOException
1069   {
1070     // See if already set
1071     if (factory != null)
1072       throw new SocketException("SocketImplFactory already defined");
1073
1074     // Check permissions
1075     SecurityManager sm = System.getSecurityManager();
1076     if (sm != null)
1077       sm.checkSetFactory();
1078
1079     if (fac == null)
1080       throw new SocketException("SocketImplFactory cannot be null");
1081
1082     factory = fac;
1083   }
1084
1085   /**
1086    * Closes the input side of the socket stream.
1087    *
1088    * @exception IOException If an error occurs.
1089    *
1090    * @since 1.3
1091    */
1092   public void shutdownInput() throws IOException
1093   {
1094     if (isClosed())
1095       throw new SocketException("socket is closed");
1096
1097     getImpl().shutdownInput();
1098     inputShutdown = true;
1099   }
1100
1101   /**
1102    * Closes the output side of the socket stream.
1103    *
1104    * @exception IOException If an error occurs.
1105    *
1106    * @since 1.3
1107    */
1108   public void shutdownOutput() throws IOException
1109   {
1110     if (isClosed())
1111       throw new SocketException("socket is closed");
1112
1113     getImpl().shutdownOutput();
1114     outputShutdown = true;
1115   }
1116
1117   /**
1118    * Returns the socket channel associated with this socket.
1119    *
1120    * @return the associated socket channel,
1121    * null if no associated channel exists
1122    *
1123    * @since 1.4
1124    */
1125   public SocketChannel getChannel()
1126   {
1127     return null;
1128   }
1129
1130   /**
1131    * Checks if the SO_REUSEADDR option is enabled
1132    *
1133    * @return True if SO_REUSEADDR is set, false otherwise.
1134    *
1135    * @exception SocketException If an error occurs
1136    *
1137    * @since 1.4
1138    */
1139   public boolean getReuseAddress() throws SocketException
1140   {
1141     if (isClosed())
1142       throw new SocketException("socket is closed");
1143
1144     Object reuseaddr = getImpl().getOption(SocketOptions.SO_REUSEADDR);
1145
1146     if (! (reuseaddr instanceof Boolean))
1147       throw new SocketException("Internal Error");
1148
1149     return ((Boolean) reuseaddr).booleanValue();
1150   }
1151
1152   /**
1153    * Enables/Disables the SO_REUSEADDR option
1154    *
1155    * @param reuseAddress true if SO_REUSEADDR should be enabled,
1156    * false otherwise
1157    *
1158    * @exception SocketException If an error occurs
1159    *
1160    * @since 1.4
1161    */
1162   public void setReuseAddress(boolean reuseAddress) throws SocketException
1163   {
1164     if (isClosed())
1165       throw new SocketException("socket is closed");
1166
1167     getImpl().setOption(SocketOptions.SO_REUSEADDR,
1168                         Boolean.valueOf(reuseAddress));
1169   }
1170
1171   /**
1172    * Returns the current traffic class
1173    *
1174    * @return The current traffic class.
1175    *
1176    * @exception SocketException If an error occurs
1177    *
1178    * @see Socket#setTrafficClass(int tc)
1179    *
1180    * @since 1.4
1181    */
1182   public int getTrafficClass() throws SocketException
1183   {
1184     if (isClosed())
1185       throw new SocketException("socket is closed");
1186
1187     Object obj = getImpl().getOption(SocketOptions.IP_TOS);
1188
1189     if (obj instanceof Integer)
1190       return ((Integer) obj).intValue();
1191     else
1192       throw new SocketException("Unexpected type");
1193   }
1194
1195   /**
1196    * Sets the traffic class value
1197    *
1198    * @param tc The traffic class
1199    *
1200    * @exception SocketException If an error occurs
1201    * @exception IllegalArgumentException If tc value is illegal
1202    *
1203    * @see Socket#getTrafficClass()
1204    *
1205    * @since 1.4
1206    */
1207   public void setTrafficClass(int tc) throws SocketException
1208   {
1209     if (isClosed())
1210       throw new SocketException("socket is closed");
1211
1212     if (tc < 0 || tc > 255)
1213       throw new IllegalArgumentException();
1214
1215     getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
1216   }
1217
1218   /**
1219    * Checks if the socket is connected
1220    *
1221    * @return True if socket is connected, false otherwise.
1222    *
1223    * @since 1.4
1224    */
1225   public boolean isConnected()
1226   {
1227     try
1228       {
1229         if (getImpl() == null)
1230           return false;
1231
1232         return getImpl().getInetAddress() != null;
1233       }
1234     catch (SocketException e)
1235       {
1236         return false;
1237       }
1238   }
1239
1240   /**
1241    * Checks if the socket is already bound.
1242    *
1243    * @return True if socket is bound, false otherwise.
1244    *
1245    * @since 1.4
1246    */
1247   public boolean isBound()
1248   {
1249     return bound;
1250   }
1251
1252   /**
1253    * Checks if the socket is closed.
1254    *
1255    * @return True if socket is closed, false otherwise.
1256    *
1257    * @since 1.4
1258    */
1259   public boolean isClosed()
1260   {
1261     return impl == null;
1262   }
1263
1264   /**
1265    * Checks if the socket's input stream is shutdown
1266    *
1267    * @return True if input is shut down.
1268    *
1269    * @since 1.4
1270    */
1271   public boolean isInputShutdown()
1272   {
1273     return inputShutdown;
1274   }
1275
1276   /**
1277    * Checks if the socket's output stream is shutdown
1278    *
1279    * @return True if output is shut down.
1280    *
1281    * @since 1.4
1282    */
1283   public boolean isOutputShutdown()
1284   {
1285     return outputShutdown;
1286   }
1287 }