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