Socket.java 35.4 KB
Newer Older
1
/* Socket.java -- Client socket implementation
2 3
   Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004
   Free Software Foundation, Inc.
4 5 6 7 8 9 10

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
11

12 13 14 15 16 17 18 19 20 21
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */
Tom Tromey committed
38

39
package java.net;
Tom Tromey committed
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 48
import java.nio.channels.SocketChannel;

Tom Tromey committed
49

50 51 52
/* Written using on-line Java Platform 1.2 API Specification.
 * Status:  I believe all methods are implemented.
 */
Tom Tromey committed
53 54

/**
55 56 57 58 59
 * This class models a client site socket.  A socket is a TCP/IP endpoint
 * for network communications conceptually similar to a file handle.
 * <p>
 * This class does not actually do any work.  Instead, it redirects all of
 * its calls to a socket implementation object which implements the
60 61
 * <code>SocketImpl</code> interface.  The implementation class is
 * instantiated by factory class that implements the
62 63
 * <code>SocketImplFactory interface</code>.  A default
 * 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 66 67 68 69 70
 * done once per virtual machine.  If a subsequent attempt is made to set the
 * factory, a <code>SocketException</code> will be thrown.
 *
 * @author Aaron M. Renn (arenn@urbanophile.com)
 * @author Per Bothner (bothner@cygnus.com)
 */
Tom Tromey committed
71 72
public class Socket
{
73 74 75 76
  /**
   * This is the user SocketImplFactory for this class.  If this variable is
   * null, a default factory is used.
   */
Tom Tromey committed
77
  static SocketImplFactory factory;
78 79 80 81

  /**
   * The implementation object to which calls are redirected
   */
82 83
  // package-private because ServerSocket.implAccept() needs to access it.
  SocketImpl impl;
Tom Tromey committed
84

85
  /**
86 87
   * True if socket implementation was created by calling their
   * create() method.
88
   */
89 90
  // package-private because ServerSocket.implAccept() needs to access it.
  boolean implCreated;
91 92 93 94 95

  /**
   * True if the socket is bound.
   */
  private boolean bound;
96

97 98 99 100 101 102 103 104 105
  /**
   * True if input is shutdown.
   */
  private boolean inputShutdown;

  /**
   * True if output is shutdown.
   */
  private boolean outputShutdown;
106

107
  /**
108 109
   * Initializes a new instance of <code>Socket</code> object without
   * 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()
Tom Tromey committed
116
  {
117 118 119 120
    if (factory != null)
      impl = factory.createSocketImpl();
    else
      impl = new PlainSocketImpl();
Tom Tromey committed
121 122
  }

123 124 125
  /**
   * Initializes a new instance of <code>Socket</code> object without
   * connecting to a remote host.  This is useful for subclasses of socket
126
   * that might want this behavior.
127 128 129
   * <p>
   * Additionally, this socket will be created using the supplied
   * implementation class instead the default class or one returned by a
130 131
   * factory.  If this value is <code>null</code>, the default Socket
   * implementation is used.
132 133 134 135 136
   *
   * @param impl The <code>SocketImpl</code> to use for this
   *             <code>Socket</code>
   *
   * @exception SocketException If an error occurs
137 138
   *
   * @since 1.1
139
   */
140
  protected Socket(SocketImpl impl) throws SocketException
Tom Tromey committed
141
  {
142 143 144 145
    if (impl == null)
      this.impl = new PlainSocketImpl();
    else
      this.impl = impl;
Tom Tromey committed
146 147
  }

148
  /**
149
   * Initializes a new instance of <code>Socket</code> and connects to the
150 151 152 153 154 155 156 157
   * hostname and port specified as arguments.
   *
   * @param host The name of the host to connect to
   * @param port The port number to connect to
   *
   * @exception UnknownHostException If the hostname cannot be resolved to a
   * network address.
   * @exception IOException If an error occurs
158 159
   * @exception SecurityException If a security manager exists and its
   * checkConnect method doesn't allow the operation
160
   */
161
  public Socket(String host, int port)
Tom Tromey committed
162 163
    throws UnknownHostException, IOException
  {
164
    this(InetAddress.getByName(host), port, null, 0, true);
Tom Tromey committed
165 166
  }

167
  /**
168
   * Initializes a new instance of <code>Socket</code> and connects to the
169 170 171 172 173 174
   * address and port number specified as arguments.
   *
   * @param address The address to connect to
   * @param port The port number to connect to
   *
   * @exception IOException If an error occurs
175 176
   * @exception SecurityException If a security manager exists and its
   * checkConnect method doesn't allow the operation
177
   */
178
  public Socket(InetAddress address, int port) throws IOException
Tom Tromey committed
179
  {
180
    this(address, port, null, 0, true);
Tom Tromey committed
181 182
  }

183
  /**
184 185
   * Initializes a new instance of <code>Socket</code> that connects to the
   * named host on the specified port and binds to the specified local address
186 187 188 189
   * and port.
   *
   * @param host The name of the remote host to connect to.
   * @param port The remote port to connect to.
190
   * @param localAddr The local address to bind to.
191 192 193 194 195 196
   * @param localPort The local port to bind to.
   *
   * @exception SecurityException If the <code>SecurityManager</code>
   * exists and does not allow a connection to the specified host/port or
   * binding to the specified local host/port.
   * @exception IOException If a connection error occurs.
197 198
   *
   * @since 1.1
199
   */
200 201
  public Socket(String host, int port, InetAddress localAddr, int localPort)
    throws IOException
Tom Tromey committed
202
  {
203
    this(InetAddress.getByName(host), port, localAddr, localPort, true);
Tom Tromey committed
204 205
  }

206
  /**
207 208
   * Initializes a new instance of <code>Socket</code> and connects to the
   * address and port number specified as arguments, plus binds to the
209 210 211 212 213 214 215 216
   * specified local address and port.
   *
   * @param address The remote address to connect to
   * @param port The remote port to connect to
   * @param localAddr The local address to connect to
   * @param localPort The local port to connect to
   *
   * @exception IOException If an error occurs
217 218
   * @exception SecurityException If a security manager exists and its
   * checkConnect method doesn't allow the operation
219 220
   *
   * @since 1.1
221
   */
222 223
  public Socket(InetAddress address, int port, InetAddress localAddr,
                int localPort) throws IOException
Tom Tromey committed
224
  {
225
    this(address, port, localAddr, localPort, true);
Tom Tromey committed
226 227 228
  }

  /**
229 230 231
   * Initializes a new instance of <code>Socket</code> and connects to the
   * hostname and port specified as arguments.  If the stream argument is set
   * to <code>true</code>, then a stream socket is created.  If it is
232 233 234 235 236 237 238 239
   * <code>false</code>, a datagram socket is created.
   *
   * @param host The name of the host to connect to
   * @param port The port to connect to
   * @param stream <code>true</code> for a stream socket, <code>false</code>
   * for a datagram socket
   *
   * @exception IOException If an error occurs
240 241
   * @exception SecurityException If a security manager exists and its
   * checkConnect method doesn't allow the operation
242 243 244
   *
   * @deprecated Use the <code>DatagramSocket</code> class to create
   * datagram oriented sockets.
Tom Tromey committed
245
   */
246 247
  public Socket(String host, int port, boolean stream)
    throws IOException
Tom Tromey committed
248
  {
249
    this(InetAddress.getByName(host), port, null, 0, stream);
Tom Tromey committed
250 251 252
  }

  /**
253 254 255
   * Initializes a new instance of <code>Socket</code> and connects to the
   * address and port number specified as arguments.  If the stream param is
   * <code>true</code>, a stream socket will be created, otherwise a datagram
256 257 258 259
   * socket is created.
   *
   * @param host The address to connect to
   * @param port The port number to connect to
260
   * @param stream <code>true</code> to create a stream socket,
261 262 263
   * <code>false</code> to create a datagram socket.
   *
   * @exception IOException If an error occurs
264 265
   * @exception SecurityException If a security manager exists and its
   * checkConnect method doesn't allow the operation
266 267 268
   *
   * @deprecated Use the <code>DatagramSocket</code> class to create
   * datagram oriented sockets.
Tom Tromey committed
269
   */
270 271
  public Socket(InetAddress host, int port, boolean stream)
    throws IOException
Tom Tromey committed
272
  {
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    this(host, port, null, 0, stream);
  }

  /**
   * This constructor is where the real work takes place.  Connect to the
   * specified address and port.  Use default local values if not specified,
   * otherwise use the local host and port passed in.  Create as stream or
   * datagram based on "stream" argument.
   * <p>
   *
   * @param raddr The remote address to connect to
   * @param rport The remote port to connect to
   * @param laddr The local address to connect to
   * @param lport The local port to connect to
   * @param stream true for a stream socket, false for a datagram socket
   *
   * @exception IOException If an error occurs
290 291
   * @exception SecurityException If a security manager exists and its
   * checkConnect method doesn't allow the operation
292 293 294 295 296
   */
  private Socket(InetAddress raddr, int rport, InetAddress laddr, int lport,
                 boolean stream) throws IOException
  {
    this();
297

298 299 300 301
    SecurityManager sm = System.getSecurityManager();
    if (sm != null)
      sm.checkConnect(raddr.getHostName(), rport);

302 303
    // bind socket
    SocketAddress bindaddr =
304 305 306
      laddr == null ? null : new InetSocketAddress(laddr, lport);
    bind(bindaddr);

307
    // connect socket
308
    connect(new InetSocketAddress(raddr, rport));
309

310 311 312
    // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port,
    // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as
    // that default.  JDK 1.2 doc infers not to do a bind.
Tom Tromey committed
313 314
  }

315
  private SocketImpl getImpl() throws SocketException
316 317 318
  {
    try
      {
319
	if (! implCreated)
320 321 322 323 324 325 326 327 328 329 330 331 332
	  {
	    impl.create(true);
	    implCreated = true;
	  }
      }
    catch (IOException e)
      {
	throw new SocketException(e.getMessage());
      }

    return impl;
  }

333
  /**
334 335 336 337
   * Binds the socket to the givent local address/port
   *
   * @param bindpoint The address/port to bind to
   *
338 339 340 341
   * @exception IOException If an error occurs
   * @exception SecurityException If a security manager exists and its
   * checkConnect method doesn't allow the operation
   * @exception IllegalArgumentException If the address type is not supported
342
   *
343 344
   * @since 1.4
   */
345
  public void bind(SocketAddress bindpoint) throws IOException
346
  {
347 348
    if (isClosed())
      throw new SocketException("socket is closed");
349 350 351 352

    // XXX: JDK 1.4.1 API documentation says that if bindpoint is null the
    // socket will be bound to an ephemeral port and a valid local address.
    if (bindpoint == null)
353 354 355 356
      bindpoint = new InetSocketAddress(InetAddress.ANY_IF, 0);

    if (! (bindpoint instanceof InetSocketAddress))
      throw new IllegalArgumentException();
357 358

    InetSocketAddress tmp = (InetSocketAddress) bindpoint;
359

360 361 362
    // bind to address/port
    try
      {
363
	getImpl().bind(tmp.getAddress(), tmp.getPort());
364
	bound = true;
365 366 367
      }
    catch (IOException exception)
      {
368 369
	close();
	throw exception;
370 371 372
      }
    catch (RuntimeException exception)
      {
373 374
	close();
	throw exception;
375 376 377
      }
    catch (Error error)
      {
378 379
	close();
	throw error;
380
      }
381
  }
382

383 384 385 386 387 388
  /**
   * Connects the socket with a remote address.
   *
   * @param endpoint The address to connect to
   *
   * @exception IOException If an error occurs
389
   * @exception IllegalArgumentException If the addess type is not supported
390 391
   * @exception IllegalBlockingModeException If this socket has an associated
   * channel, and the channel is in non-blocking mode
392
   *
393 394
   * @since 1.4
   */
395
  public void connect(SocketAddress endpoint) throws IOException
396
  {
397
    connect(endpoint, 0);
398 399 400 401 402 403 404 405
  }

  /**
   * Connects the socket with a remote address. A timeout of zero is
   * interpreted as an infinite timeout. The connection will then block
   * until established or an error occurs.
   *
   * @param endpoint The address to connect to
406
   * @param timeout The length of the timeout in milliseconds, or
407
   * 0 to indicate no timeout.
408 409
   *
   * @exception IOException If an error occurs
410
   * @exception IllegalArgumentException If the address type is not supported
411 412
   * @exception IllegalBlockingModeException If this socket has an associated
   * channel, and the channel is in non-blocking mode
413
   * @exception SocketTimeoutException If the timeout is reached
414
   *
415 416
   * @since 1.4
   */
417
  public void connect(SocketAddress endpoint, int timeout)
418 419
    throws IOException
  {
420 421
    if (isClosed())
      throw new SocketException("socket is closed");
422

423
    if (! (endpoint instanceof InetSocketAddress))
424
      throw new IllegalArgumentException("unsupported address type");
425

426 427 428 429
    // The Sun spec says that if we have an associated channel and
    // it is in non-blocking mode, we throw an IllegalBlockingModeException.
    // However, in our implementation if the channel itself initiated this
    // operation, then we must honor it regardless of its blocking mode.
430 431 432 433 434 435
    if (getChannel() != null && ! getChannel().isBlocking()
        && ! ((PlainSocketImpl) getImpl()).isInChannelOperation())
      throw new IllegalBlockingModeException();

    if (! isBound())
      bind(null);
436 437 438

    try
      {
439
	getImpl().connect(endpoint, timeout);
440 441 442
      }
    catch (IOException exception)
      {
443 444
	close();
	throw exception;
445 446 447
      }
    catch (RuntimeException exception)
      {
448 449
	close();
	throw exception;
450 451 452
      }
    catch (Error error)
      {
453 454
	close();
	throw error;
455
      }
456 457 458
  }

  /**
459 460 461 462 463
   * Returns the address of the remote end of the socket.  If this socket
   * is not connected, then <code>null</code> is returned.
   *
   * @return The remote address this socket is connected to
   */
464
  public InetAddress getInetAddress()
Tom Tromey committed
465
  {
466
    if (! isConnected())
467 468 469 470 471 472 473 474 475 476 477 478
      return null;

    try
      {
	return getImpl().getInetAddress();
      }
    catch (SocketException e)
      {
	// This cannot happen as we are connected.
      }

    return null;
Tom Tromey committed
479 480
  }

481 482
  /**
   * Returns the local address to which this socket is bound.  If this socket
483 484
   * is not connected, then a wildcard address, for which
   * @see isAnyLocalAddress() is <code>true</code>, is returned.
485 486
   *
   * @return The local address
487 488
   *
   * @since 1.1
489
   */
490
  public InetAddress getLocalAddress()
Tom Tromey committed
491
  {
Michael Koch committed
492
    if (! isBound())
493
      return InetAddress.ANY_IF;
Michael Koch committed
494

495
    InetAddress addr = null;
496

Warren Levy committed
497 498
    try
      {
499
	addr = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
Warren Levy committed
500
      }
501
    catch (SocketException e)
Warren Levy committed
502
      {
503 504 505 506
	// (hopefully) shouldn't happen
	// throw new java.lang.InternalError
	//      ("Error in PlainSocketImpl.getOption");
	return null;
Warren Levy committed
507
      }
508 509 510 511 512 513 514 515 516 517 518

    // FIXME: According to libgcj, checkConnect() is supposed to be called
    // before performing this operation.  Problems: 1) We don't have the
    // addr until after we do it, so we do a post check.  2). The docs I
    // see don't require this in the Socket case, only DatagramSocket, but
    // we'll assume they mean both.
    SecurityManager sm = System.getSecurityManager();
    if (sm != null)
      sm.checkConnect(addr.getHostName(), getLocalPort());

    return addr;
Tom Tromey committed
519 520
  }

521 522
  /**
   * Returns the port number of the remote end of the socket connection.  If
523
   * this socket is not connected, then 0 is returned.
524 525 526
   *
   * @return The remote port this socket is connected to
   */
527
  public int getPort()
Tom Tromey committed
528
  {
529
    if (! isConnected())
530
      return 0;
531 532 533

    try
      {
Michael Koch committed
534
	return getImpl().getPort();
535 536 537 538 539
      }
    catch (SocketException e)
      {
	// This cannot happen as we are connected.
      }
540 541

    return -1;
Tom Tromey committed
542 543
  }

544 545 546 547 548 549
  /**
   * Returns the local port number to which this socket is bound.  If this
   * socket is not connected, then -1 is returned.
   *
   * @return The local port
   */
550
  public int getLocalPort()
Tom Tromey committed
551
  {
552
    if (! isBound())
553
      return -1;
554

555 556 557 558 559 560 561 562 563
    try
      {
	if (getImpl() != null)
	  return getImpl().getLocalPort();
      }
    catch (SocketException e)
      {
	// This cannot happen as we are bound.
      }
564 565

    return -1;
Tom Tromey committed
566 567
  }

568
  /**
569 570 571
   * Returns local socket address.
   *
   * @return the local socket address, null if not bound
572 573 574 575 576
   *
   * @since 1.4
   */
  public SocketAddress getLocalSocketAddress()
  {
577
    if (! isBound())
578
      return null;
579 580

    InetAddress addr = getLocalAddress();
581 582 583

    try
      {
584
	return new InetSocketAddress(addr, getImpl().getLocalPort());
585 586 587 588 589 590
      }
    catch (SocketException e)
      {
	// This cannot happen as we are bound.
	return null;
      }
591 592 593
  }

  /**
594 595 596
   * Returns the remote socket address.
   *
   * @return the remote socket address, null of not connected
597 598 599 600 601
   *
   * @since 1.4
   */
  public SocketAddress getRemoteSocketAddress()
  {
602
    if (! isConnected())
603 604
      return null;

605 606
    try
      {
607 608
	return new InetSocketAddress(getImpl().getInetAddress(),
	                             getImpl().getPort());
609 610 611 612 613 614
      }
    catch (SocketException e)
      {
	// This cannot happen as we are connected.
	return null;
      }
615 616 617
  }

  /**
618 619 620 621 622 623
   * Returns an InputStream for reading from this socket.
   *
   * @return The InputStream object
   *
   * @exception IOException If an error occurs or Socket is not connected
   */
624
  public InputStream getInputStream() throws IOException
Tom Tromey committed
625
  {
626 627
    if (isClosed())
      throw new SocketException("socket is closed");
628 629

    if (! isConnected())
630
      throw new IOException("not connected");
631

632
    return getImpl().getInputStream();
Tom Tromey committed
633 634
  }

635 636 637 638 639 640 641
  /**
   * Returns an OutputStream for writing to this socket.
   *
   * @return The OutputStream object
   *
   * @exception IOException If an error occurs or Socket is not connected
   */
642
  public OutputStream getOutputStream() throws IOException
Tom Tromey committed
643
  {
644 645
    if (isClosed())
      throw new SocketException("socket is closed");
646 647

    if (! isConnected())
648
      throw new IOException("not connected");
649

650
    return getImpl().getOutputStream();
Tom Tromey committed
651 652
  }

653
  /**
654
   * Sets the TCP_NODELAY option on the socket.
655 656
   *
   * @param on true to enable, false to disable
657
   *
658
   * @exception SocketException If an error occurs or Socket is not connected
659 660
   *
   * @since 1.1
661
   */
662
  public void setTcpNoDelay(boolean on) throws SocketException
Tom Tromey committed
663
  {
664 665
    if (isClosed())
      throw new SocketException("socket is closed");
666

667
    getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
Tom Tromey committed
668 669
  }

670
  /**
671
   * Tests whether or not the TCP_NODELAY option is set on the socket.
672 673 674 675 676
   * Returns true if enabled, false if disabled. When on it disables the
   * Nagle algorithm which means that packets are always send immediatly and
   * never merged together to reduce network trafic.
   *
   * @return Whether or not TCP_NODELAY is set
677
   *
678
   * @exception SocketException If an error occurs or Socket not connected
679 680
   *
   * @since 1.1
681
   */
Tom Tromey committed
682 683
  public boolean getTcpNoDelay() throws SocketException
  {
684 685
    if (isClosed())
      throw new SocketException("socket is closed");
686

687
    Object on = getImpl().getOption(SocketOptions.TCP_NODELAY);
688

689
    if (on instanceof Boolean)
690
      return (((Boolean) on).booleanValue());
691 692
    else
      throw new SocketException("Internal Error");
Tom Tromey committed
693 694
  }

695
  /**
696
   * Sets the value of the SO_LINGER option on the socket.  If the
697 698 699 700 701 702 703
   * SO_LINGER option is set on a socket and there is still data waiting to
   * be sent when the socket is closed, then the close operation will block
   * until either that data is delivered or until the timeout period
   * expires.  The linger interval is specified in hundreths of a second
   * (platform specific?)
   *
   * @param on true to enable SO_LINGER, false to disable
704
   * @param linger The SO_LINGER timeout in hundreths of a second or -1 if
705 706 707
   * SO_LINGER not set.
   *
   * @exception SocketException If an error occurs or Socket not connected
708
   * @exception IllegalArgumentException If linger is negative
709 710
   *
   * @since 1.1
711
   */
Tom Tromey committed
712 713
  public void setSoLinger(boolean on, int linger) throws SocketException
  {
714 715
    if (isClosed())
      throw new SocketException("socket is closed");
716 717

    if (on)
Warren Levy committed
718
      {
719 720
	if (linger < 0)
	  throw new IllegalArgumentException("SO_LINGER must be >= 0");
721

722 723
	if (linger > 65535)
	  linger = 65535;
724

725
	getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
726
      }
Warren Levy committed
727
    else
728
      getImpl().setOption(SocketOptions.SO_LINGER, Boolean.valueOf(false));
Tom Tromey committed
729 730
  }

731
  /**
732
   * Returns the value of the SO_LINGER option on the socket.  If the
733 734 735 736 737 738 739
   * SO_LINGER option is set on a socket and there is still data waiting to
   * be sent when the socket is closed, then the close operation will block
   * until either that data is delivered or until the timeout period
   * expires.  This method either returns the timeouts (in hundredths of
   * of a second (platform specific?)) if SO_LINGER is set, or -1 if
   * SO_LINGER is not set.
   *
740
   * @return The SO_LINGER timeout in hundreths of a second or -1
741 742 743
   * if SO_LINGER not set
   *
   * @exception SocketException If an error occurs or Socket is not connected
744 745
   *
   * @since 1.1
746
   */
747
  public int getSoLinger() throws SocketException
Tom Tromey committed
748
  {
749 750
    if (isClosed())
      throw new SocketException("socket is closed");
751

752 753
    Object linger = getImpl().getOption(SocketOptions.SO_LINGER);

754
    if (linger instanceof Integer)
755
      return (((Integer) linger).intValue());
Warren Levy committed
756 757
    else
      return -1;
Tom Tromey committed
758 759
  }

760
  /**
761 762 763 764 765 766 767 768 769
   * Sends urgent data through the socket
   *
   * @param data The data to send.
   * Only the lowest eight bits of data are sent
   *
   * @exception IOException If an error occurs
   *
   * @since 1.4
   */
770
  public void sendUrgentData(int data) throws IOException
771
  {
772 773
    if (isClosed())
      throw new SocketException("socket is closed");
774 775

    getImpl().sendUrgentData(data);
776 777 778
  }

  /**
779
   * Enables/disables the SO_OOBINLINE option
780 781 782
   *
   * @param on True if SO_OOBLINE should be enabled
   *
783
   * @exception SocketException If an error occurs
784
   *
785 786
   * @since 1.4
   */
787
  public void setOOBInline(boolean on) throws SocketException
788
  {
789 790
    if (isClosed())
      throw new SocketException("socket is closed");
791

792
    getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on));
793 794 795 796
  }

  /**
   * Returns the current setting of the SO_OOBINLINE option for this socket
797
   *
798 799
   * @return True if SO_OOBINLINE is set, false otherwise.
   *
800
   * @exception SocketException If an error occurs
801
   *
802 803
   * @since 1.4
   */
804
  public boolean getOOBInline() throws SocketException
805
  {
806 807
    if (isClosed())
      throw new SocketException("socket is closed");
808

809
    Object buf = getImpl().getOption(SocketOptions.SO_OOBINLINE);
810 811

    if (buf instanceof Boolean)
812
      return (((Boolean) buf).booleanValue());
813 814 815
    else
      throw new SocketException("Internal Error: Unexpected type");
  }
816

817
  /**
818 819 820 821
   * Sets the value of the SO_TIMEOUT option on the socket.  If this value
   * is set, and an read/write is performed that does not complete within
   * the timeout period, a short count is returned (or an EWOULDBLOCK signal
   * would be sent in Unix if no data had been read).  A value of 0 for
822
   * this option implies that there is no timeout (ie, operations will
823 824
   * block forever).  On systems that have separate read and write timeout
   * values, this method returns the read timeout.  This
825
   * value is in milliseconds.
826
   *
827
   * @param timeout The length of the timeout in milliseconds, or
828
   * 0 to indicate no timeout.
829 830
   *
   * @exception SocketException If an error occurs or Socket not connected
831 832
   *
   * @since 1.1
833
   */
834
  public synchronized void setSoTimeout(int timeout) throws SocketException
Tom Tromey committed
835
  {
836 837
    if (isClosed())
      throw new SocketException("socket is closed");
838

Warren Levy committed
839
    if (timeout < 0)
840
      throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0");
841

842
    getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
Tom Tromey committed
843 844
  }

845 846 847 848 849
  /**
   * Returns the value of the SO_TIMEOUT option on the socket.  If this value
   * is set, and an read/write is performed that does not complete within
   * the timeout period, a short count is returned (or an EWOULDBLOCK signal
   * would be sent in Unix if no data had been read).  A value of 0 for
850
   * this option implies that there is no timeout (ie, operations will
851 852 853 854
   * block forever).  On systems that have separate read and write timeout
   * values, this method returns the read timeout.  This
   * value is in thousandths of a second (implementation specific?).
   *
855
   * @return The length of the timeout in thousandth's of a second or 0
856 857 858
   * if not set
   *
   * @exception SocketException If an error occurs or Socket not connected
859 860
   *
   * @since 1.1
861
   */
862
  public synchronized int getSoTimeout() throws SocketException
Tom Tromey committed
863
  {
864 865
    if (isClosed())
      throw new SocketException("socket is closed");
866

867
    Object timeout = getImpl().getOption(SocketOptions.SO_TIMEOUT);
868
    if (timeout instanceof Integer)
869
      return (((Integer) timeout).intValue());
Warren Levy committed
870 871
    else
      return 0;
Tom Tromey committed
872 873
  }

874 875 876 877 878 879 880 881
  /**
   * This method sets the value for the system level socket option
   * SO_SNDBUF to the specified value.  Note that valid values for this
   * option are specific to a given operating system.
   *
   * @param size The new send buffer size.
   *
   * @exception SocketException If an error occurs or Socket not connected
882
   * @exception IllegalArgumentException If size is 0 or negative
883
   *
884
   * @since 1.2
885
   */
886
  public void setSendBufferSize(int size) throws SocketException
Tom Tromey committed
887
  {
888 889
    if (isClosed())
      throw new SocketException("socket is closed");
890

Warren Levy committed
891
    if (size <= 0)
892
      throw new IllegalArgumentException("SO_SNDBUF value must be > 0");
893

894
    getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
Tom Tromey committed
895 896
  }

897 898 899 900 901 902 903 904 905
  /**
   * This method returns the value of the system level socket option
   * SO_SNDBUF, which is used by the operating system to tune buffer
   * sizes for data transfers.
   *
   * @return The send buffer size.
   *
   * @exception SocketException If an error occurs or socket not connected
   *
906
   * @since 1.2
907
   */
908
  public int getSendBufferSize() throws SocketException
Tom Tromey committed
909
  {
910 911
    if (isClosed())
      throw new SocketException("socket is closed");
912

913
    Object buf = getImpl().getOption(SocketOptions.SO_SNDBUF);
914 915

    if (buf instanceof Integer)
916
      return (((Integer) buf).intValue());
917 918
    else
      throw new SocketException("Internal Error: Unexpected type");
Tom Tromey committed
919 920
  }

921 922 923 924 925 926 927 928
  /**
   * This method sets the value for the system level socket option
   * SO_RCVBUF to the specified value.  Note that valid values for this
   * option are specific to a given operating system.
   *
   * @param size The new receive buffer size.
   *
   * @exception SocketException If an error occurs or Socket is not connected
929
   * @exception IllegalArgumentException If size is 0 or negative
930
   *
931
   * @since 1.2
932
   */
933
  public void setReceiveBufferSize(int size) throws SocketException
Tom Tromey committed
934
  {
935 936
    if (isClosed())
      throw new SocketException("socket is closed");
937

938 939
    if (size <= 0)
      throw new IllegalArgumentException("SO_RCVBUF value must be > 0");
940

941
    getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
Tom Tromey committed
942 943
  }

944 945 946 947 948 949 950 951 952
  /**
   * This method returns the value of the system level socket option
   * SO_RCVBUF, which is used by the operating system to tune buffer
   * sizes for data transfers.
   *
   * @return The receive buffer size.
   *
   * @exception SocketException If an error occurs or Socket is not connected
   *
953
   * @since 1.2
954
   */
955
  public int getReceiveBufferSize() throws SocketException
Tom Tromey committed
956
  {
957 958
    if (isClosed())
      throw new SocketException("socket is closed");
959

960
    Object buf = getImpl().getOption(SocketOptions.SO_RCVBUF);
961 962

    if (buf instanceof Integer)
963
      return (((Integer) buf).intValue());
964 965
    else
      throw new SocketException("Internal Error: Unexpected type");
Tom Tromey committed
966 967
  }

968
  /**
969 970 971 972 973 974 975
   * This method sets the value for the socket level socket option
   * SO_KEEPALIVE.
   *
   * @param on True if SO_KEEPALIVE should be enabled
   *
   * @exception SocketException If an error occurs or Socket is not connected
   *
976
   * @since 1.3
977
   */
978
  public void setKeepAlive(boolean on) throws SocketException
979
  {
980 981
    if (isClosed())
      throw new SocketException("socket is closed");
982

983
    getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on));
984 985 986 987 988 989 990 991 992 993
  }

  /**
   * This method returns the value of the socket level socket option
   * SO_KEEPALIVE.
   *
   * @return The setting
   *
   * @exception SocketException If an error occurs or Socket is not connected
   *
994
   * @since 1.3
995
   */
996
  public boolean getKeepAlive() throws SocketException
997
  {
998 999
    if (isClosed())
      throw new SocketException("socket is closed");
1000

1001
    Object buf = getImpl().getOption(SocketOptions.SO_KEEPALIVE);
1002 1003

    if (buf instanceof Boolean)
1004
      return (((Boolean) buf).booleanValue());
1005 1006 1007 1008 1009
    else
      throw new SocketException("Internal Error: Unexpected type");
  }

  /**
1010 1011 1012 1013
   * Closes the socket.
   *
   * @exception IOException If an error occurs
   */
1014
  public synchronized void close() throws IOException
Tom Tromey committed
1015
  {
1016
    if (isClosed())
1017
      return;
1018

1019
    getImpl().close();
1020 1021
    impl = null;
    bound = false;
1022

1023 1024
    if (getChannel() != null)
      getChannel().close();
Tom Tromey committed
1025 1026
  }

1027 1028 1029 1030 1031
  /**
   * Converts this <code>Socket</code> to a <code>String</code>.
   *
   * @return The <code>String</code> representation of this <code>Socket</code>
   */
1032
  public String toString()
Tom Tromey committed
1033
  {
1034 1035 1036
    try
      {
	if (isConnected())
1037 1038 1039
	  return ("Socket[addr=" + getImpl().getInetAddress() + ",port="
	         + getImpl().getPort() + ",localport="
	         + getImpl().getLocalPort() + "]");
1040 1041 1042 1043 1044 1045 1046
      }
    catch (SocketException e)
      {
	// This cannot happen as we are connected.
      }

    return "Socket[unconnected]";
Tom Tromey committed
1047 1048
  }

1049
  /**
1050 1051
   * Sets the <code>SocketImplFactory</code>.  This may be done only once per
   * virtual machine.  Subsequent attempts will generate a
1052
   * <code>SocketException</code>.  Note that a <code>SecurityManager</code>
1053 1054
   * check is made prior to setting the factory.  If
   * insufficient privileges exist to set the factory, then an
1055 1056
   * <code>IOException</code> will be thrown.
   *
1057 1058
   * @param fac the factory to set
   *
1059 1060 1061 1062 1063
   * @exception SecurityException If the <code>SecurityManager</code> does
   * not allow this operation.
   * @exception SocketException If the SocketImplFactory is already defined
   * @exception IOException If any other error occurs
   */
1064
  public static synchronized void setSocketImplFactory(SocketImplFactory fac)
Tom Tromey committed
1065 1066
    throws IOException
  {
1067 1068 1069 1070 1071 1072 1073 1074 1075
    // See if already set
    if (factory != null)
      throw new SocketException("SocketImplFactory already defined");

    // Check permissions
    SecurityManager sm = System.getSecurityManager();
    if (sm != null)
      sm.checkSetFactory();

1076 1077 1078
    if (fac == null)
      throw new SocketException("SocketImplFactory cannot be null");

Tom Tromey committed
1079 1080
    factory = fac;
  }
1081 1082 1083 1084 1085

  /**
   * Closes the input side of the socket stream.
   *
   * @exception IOException If an error occurs.
1086 1087
   *
   * @since 1.3
1088
   */
1089
  public void shutdownInput() throws IOException
1090
  {
1091 1092
    if (isClosed())
      throw new SocketException("socket is closed");
1093

1094
    getImpl().shutdownInput();
1095
    inputShutdown = true;
1096 1097 1098 1099 1100 1101
  }

  /**
   * Closes the output side of the socket stream.
   *
   * @exception IOException If an error occurs.
1102 1103
   *
   * @since 1.3
1104 1105 1106
   */
  public void shutdownOutput() throws IOException
  {
1107 1108
    if (isClosed())
      throw new SocketException("socket is closed");
1109

1110
    getImpl().shutdownOutput();
1111
    outputShutdown = true;
1112
  }
1113 1114 1115 1116

  /**
   * Returns the socket channel associated with this socket.
   *
1117 1118
   * @return the associated socket channel,
   * null if no associated channel exists
1119 1120
   *
   * @since 1.4
1121 1122 1123
   */
  public SocketChannel getChannel()
  {
1124
    return null;
1125
  }
1126 1127 1128 1129

  /**
   * Checks if the SO_REUSEADDR option is enabled
   *
1130 1131
   * @return True if SO_REUSEADDR is set, false otherwise.
   *
1132 1133 1134 1135
   * @exception SocketException If an error occurs
   *
   * @since 1.4
   */
1136
  public boolean getReuseAddress() throws SocketException
1137
  {
1138 1139
    if (isClosed())
      throw new SocketException("socket is closed");
1140

1141
    Object reuseaddr = getImpl().getOption(SocketOptions.SO_REUSEADDR);
1142

1143 1144 1145 1146
    if (! (reuseaddr instanceof Boolean))
      throw new SocketException("Internal Error");

    return ((Boolean) reuseaddr).booleanValue();
1147 1148 1149 1150 1151
  }

  /**
   * Enables/Disables the SO_REUSEADDR option
   *
1152 1153 1154
   * @param reuseAddress true if SO_REUSEADDR should be enabled,
   * false otherwise
   *
1155 1156 1157 1158
   * @exception SocketException If an error occurs
   *
   * @since 1.4
   */
1159
  public void setReuseAddress(boolean reuseAddress) throws SocketException
1160
  {
Michael Koch committed
1161 1162 1163
    if (isClosed())
      throw new SocketException("socket is closed");

1164 1165
    getImpl().setOption(SocketOptions.SO_REUSEADDR,
                        Boolean.valueOf(reuseAddress));
1166 1167 1168 1169 1170
  }

  /**
   * Returns the current traffic class
   *
1171
   * @return The current traffic class.
1172
   *
1173 1174
   * @exception SocketException If an error occurs
   *
1175
   * @see Socket#setTrafficClass(int tc)
1176 1177 1178
   *
   * @since 1.4
   */
1179
  public int getTrafficClass() throws SocketException
1180
  {
1181 1182
    if (isClosed())
      throw new SocketException("socket is closed");
1183

1184
    Object obj = getImpl().getOption(SocketOptions.IP_TOS);
1185 1186

    if (obj instanceof Integer)
1187
      return ((Integer) obj).intValue();
1188
    else
1189
      throw new SocketException("Unexpected type");
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
  }

  /**
   * Sets the traffic class value
   *
   * @param tc The traffic class
   *
   * @exception SocketException If an error occurs
   * @exception IllegalArgumentException If tc value is illegal
   *
1200
   * @see Socket#getTrafficClass()
1201 1202 1203
   *
   * @since 1.4
   */
1204
  public void setTrafficClass(int tc) throws SocketException
1205
  {
1206 1207
    if (isClosed())
      throw new SocketException("socket is closed");
1208

1209 1210 1211
    if (tc < 0 || tc > 255)
      throw new IllegalArgumentException();

1212
    getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
1213
  }
1214 1215

  /**
1216
   * Checks if the socket is connected
1217
   *
1218 1219
   * @return True if socket is connected, false otherwise.
   *
1220
   * @since 1.4
1221
   */
1222
  public boolean isConnected()
1223
  {
1224 1225
    try
      {
Michael Koch committed
1226 1227 1228
	if (getImpl() == null)
	  return false;

1229
	return getImpl().getInetAddress() != null;
1230 1231 1232 1233 1234
      }
    catch (SocketException e)
      {
	return false;
      }
1235 1236 1237
  }

  /**
1238
   * Checks if the socket is already bound.
1239
   *
1240 1241
   * @return True if socket is bound, false otherwise.
   *
1242
   * @since 1.4
1243
   */
1244
  public boolean isBound()
1245
  {
1246
    return bound;
1247
  }
1248 1249 1250

  /**
   * Checks if the socket is closed.
1251
   *
1252 1253
   * @return True if socket is closed, false otherwise.
   *
1254
   * @since 1.4
1255
   */
1256
  public boolean isClosed()
1257
  {
1258
    return impl == null;
1259 1260 1261 1262
  }

  /**
   * Checks if the socket's input stream is shutdown
1263
   *
1264
   * @return True if input is shut down.
1265
   *
1266
   * @since 1.4
1267
   */
1268
  public boolean isInputShutdown()
1269 1270 1271 1272 1273 1274
  {
    return inputShutdown;
  }

  /**
   * Checks if the socket's output stream is shutdown
1275
   *
1276
   * @return True if output is shut down.
1277
   *
1278
   * @since 1.4
1279
   */
1280
  public boolean isOutputShutdown()
1281 1282 1283
  {
    return outputShutdown;
  }
Tom Tromey committed
1284
}