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