1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.net; 28 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.OutputStream; 32 import java.io.FileDescriptor; 33 34 import dalvik.annotation.optimization.ReachabilitySensitive; 35 import dalvik.system.BlockGuard; 36 import dalvik.system.CloseGuard; 37 import dalvik.system.SocketTagger; 38 import sun.net.ConnectionResetException; 39 import sun.net.NetHooks; 40 import sun.net.ResourceManager; 41 42 /** 43 * Default Socket Implementation. This implementation does 44 * not implement any security checks. 45 * Note this class should <b>NOT</b> be public. 46 * 47 * @author Steven B. Byrne 48 */ 49 abstract class AbstractPlainSocketImpl extends SocketImpl 50 { 51 /* instance variable for SO_TIMEOUT */ 52 int timeout; // timeout in millisec 53 // Android-removed: traffic class is set through socket 54 // private int trafficClass; 55 56 private boolean shut_rd = false; 57 private boolean shut_wr = false; 58 59 private SocketInputStream socketInputStream = null; 60 private SocketOutputStream socketOutputStream = null; 61 62 /* number of threads using the FileDescriptor */ 63 protected int fdUseCount = 0; 64 65 /* lock when increment/decrementing fdUseCount */ 66 // Android-added: @ReachabilitySensitive 67 // Marked mostly because it's used where fd is, and fd isn't declared here. 68 // This adds reachabilityFences where we would if fd were annotated. 69 @ReachabilitySensitive 70 protected final Object fdLock = new Object(); 71 72 /* indicates a close is pending on the file descriptor */ 73 protected boolean closePending = false; 74 75 /* indicates connection reset state */ 76 private int CONNECTION_NOT_RESET = 0; 77 private int CONNECTION_RESET_PENDING = 1; 78 private int CONNECTION_RESET = 2; 79 private int resetState; 80 private final Object resetLock = new Object(); 81 82 /* whether this Socket is a stream (TCP) socket or not (UDP) 83 */ 84 protected boolean stream; 85 86 // BEGIN Android-removed: Android doesn't need to load native net library 87 /* 88 /** 89 * Load net library into runtime. 90 * 91 static { 92 java.security.AccessController.doPrivileged( 93 new java.security.PrivilegedAction<Void>() { 94 public Void run() { 95 System.loadLibrary("net"); 96 return null; 97 } 98 }); 99 } 100 */ 101 // END Android-removed: Android doesn't need to load native net library 102 103 // Android-added: logs a warning if socket is not closed 104 @ReachabilitySensitive 105 private final CloseGuard guard = CloseGuard.get(); 106 107 /** 108 * Creates a socket with a boolean that specifies whether this 109 * is a stream socket (true) or an unconnected UDP socket (false). 110 */ create(boolean stream)111 protected synchronized void create(boolean stream) throws IOException { 112 this.stream = stream; 113 if (!stream) { 114 ResourceManager.beforeUdpCreate(); 115 // Android-removed: socketCreate should set fd if it succeeds 116 // fd = new FileDescriptor(); 117 try { 118 socketCreate(false); 119 } catch (IOException ioe) { 120 ResourceManager.afterUdpClose(); 121 // Android-removed: b/26470377 Represent closed sockets with invalid fd, not null. 122 // fd = null; 123 throw ioe; 124 } 125 } else { 126 // Android-removed: socketCreate should set fd if it succeeds 127 // fd = new FileDescriptor(); 128 socketCreate(true); 129 } 130 if (socket != null) 131 socket.setCreated(); 132 if (serverSocket != null) 133 serverSocket.setCreated(); 134 135 // Android-added: CloseGuard 136 if (fd != null && fd.valid()) { 137 guard.open("close"); 138 } 139 } 140 141 /** 142 * Creates a socket and connects it to the specified port on 143 * the specified host. 144 * @param host the specified host 145 * @param port the specified port 146 */ connect(String host, int port)147 protected void connect(String host, int port) 148 throws UnknownHostException, IOException 149 { 150 boolean connected = false; 151 try { 152 InetAddress address = InetAddress.getByName(host); 153 this.port = port; 154 this.address = address; 155 156 connectToAddress(address, port, timeout); 157 connected = true; 158 } finally { 159 if (!connected) { 160 try { 161 close(); 162 } catch (IOException ioe) { 163 /* Do nothing. If connect threw an exception then 164 it will be passed up the call stack */ 165 } 166 } 167 } 168 } 169 170 /** 171 * Creates a socket and connects it to the specified address on 172 * the specified port. 173 * @param address the address 174 * @param port the specified port 175 */ connect(InetAddress address, int port)176 protected void connect(InetAddress address, int port) throws IOException { 177 this.port = port; 178 this.address = address; 179 180 try { 181 connectToAddress(address, port, timeout); 182 return; 183 } catch (IOException e) { 184 // everything failed 185 close(); 186 throw e; 187 } 188 } 189 190 /** 191 * Creates a socket and connects it to the specified address on 192 * the specified port. 193 * @param address the address 194 * @param timeout the timeout value in milliseconds, or zero for no timeout. 195 * @throws IOException if connection fails 196 * @throws IllegalArgumentException if address is null or is a 197 * SocketAddress subclass not supported by this socket 198 * @since 1.4 199 */ connect(SocketAddress address, int timeout)200 protected void connect(SocketAddress address, int timeout) 201 throws IOException { 202 boolean connected = false; 203 try { 204 if (address == null || !(address instanceof InetSocketAddress)) 205 throw new IllegalArgumentException("unsupported address type"); 206 InetSocketAddress addr = (InetSocketAddress) address; 207 if (addr.isUnresolved()) 208 throw new UnknownHostException(addr.getHostName()); 209 this.port = addr.getPort(); 210 this.address = addr.getAddress(); 211 212 connectToAddress(this.address, port, timeout); 213 connected = true; 214 } finally { 215 if (!connected) { 216 try { 217 close(); 218 } catch (IOException ioe) { 219 /* Do nothing. If connect threw an exception then 220 it will be passed up the call stack */ 221 } 222 } 223 } 224 } 225 connectToAddress(InetAddress address, int port, int timeout)226 private void connectToAddress(InetAddress address, int port, int timeout) throws IOException { 227 if (address.isAnyLocalAddress()) { 228 doConnect(InetAddress.getLocalHost(), port, timeout); 229 } else { 230 doConnect(address, port, timeout); 231 } 232 } 233 setOption(int opt, Object val)234 public void setOption(int opt, Object val) throws SocketException { 235 if (isClosedOrPending()) { 236 throw new SocketException("Socket Closed"); 237 } 238 // BEGIN Android-removed: Logic dealing with value type moved to socketSetOption. 239 /* 240 boolean on = true; 241 switch (opt) { 242 /* check type safety b4 going native. These should never 243 * fail, since only java.Socket* has access to 244 * PlainSocketImpl.setOption(). 245 * 246 case SO_LINGER: 247 if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean))) 248 throw new SocketException("Bad parameter for option"); 249 if (val instanceof Boolean) { 250 /* true only if disabling - enabling should be Integer * 251 on = false; 252 } 253 break; 254 case SO_TIMEOUT: 255 if (val == null || (!(val instanceof Integer))) 256 throw new SocketException("Bad parameter for SO_TIMEOUT"); 257 int tmp = ((Integer) val).intValue(); 258 if (tmp < 0) 259 throw new IllegalArgumentException("timeout < 0"); 260 timeout = tmp; 261 break; 262 case IP_TOS: 263 if (val == null || !(val instanceof Integer)) { 264 throw new SocketException("bad argument for IP_TOS"); 265 } 266 trafficClass = ((Integer)val).intValue(); 267 break; 268 case SO_BINDADDR: 269 throw new SocketException("Cannot re-bind socket"); 270 case TCP_NODELAY: 271 if (val == null || !(val instanceof Boolean)) 272 throw new SocketException("bad parameter for TCP_NODELAY"); 273 on = ((Boolean)val).booleanValue(); 274 break; 275 case SO_SNDBUF: 276 case SO_RCVBUF: 277 if (val == null || !(val instanceof Integer) || 278 !(((Integer)val).intValue() > 0)) { 279 throw new SocketException("bad parameter for SO_SNDBUF " + 280 "or SO_RCVBUF"); 281 } 282 break; 283 case SO_KEEPALIVE: 284 if (val == null || !(val instanceof Boolean)) 285 throw new SocketException("bad parameter for SO_KEEPALIVE"); 286 on = ((Boolean)val).booleanValue(); 287 break; 288 case SO_OOBINLINE: 289 if (val == null || !(val instanceof Boolean)) 290 throw new SocketException("bad parameter for SO_OOBINLINE"); 291 on = ((Boolean)val).booleanValue(); 292 break; 293 case SO_REUSEADDR: 294 if (val == null || !(val instanceof Boolean)) 295 throw new SocketException("bad parameter for SO_REUSEADDR"); 296 on = ((Boolean)val).booleanValue(); 297 break; 298 default: 299 throw new SocketException("unrecognized TCP option: " + opt); 300 } 301 socketSetOption(opt, on, val); 302 */ 303 // END Android-removed: Logic dealing with value type moved to socketSetOption. 304 // Android-added: Keep track of timeout value not handled by socketSetOption 305 if (opt == SO_TIMEOUT) { 306 timeout = (Integer) val; 307 } 308 socketSetOption(opt, val); 309 } getOption(int opt)310 public Object getOption(int opt) throws SocketException { 311 if (isClosedOrPending()) { 312 throw new SocketException("Socket Closed"); 313 } 314 if (opt == SO_TIMEOUT) { 315 return new Integer(timeout); 316 } 317 // BEGIN Android-changed: Logic dealing with value type moved to socketGetOption. 318 /* 319 int ret = 0; 320 /* 321 * The native socketGetOption() knows about 3 options. 322 * The 32 bit value it returns will be interpreted according 323 * to what we're asking. A return of -1 means it understands 324 * the option but its turned off. It will raise a SocketException 325 * if "opt" isn't one it understands. 326 * 327 328 switch (opt) { 329 case TCP_NODELAY: 330 ret = socketGetOption(opt, null); 331 return Boolean.valueOf(ret != -1); 332 case SO_OOBINLINE: 333 ret = socketGetOption(opt, null); 334 return Boolean.valueOf(ret != -1); 335 case SO_LINGER: 336 ret = socketGetOption(opt, null); 337 return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret)); 338 case SO_REUSEADDR: 339 ret = socketGetOption(opt, null); 340 return Boolean.valueOf(ret != -1); 341 case SO_BINDADDR: 342 InetAddressContainer in = new InetAddressContainer(); 343 ret = socketGetOption(opt, in); 344 return in.addr; 345 case SO_SNDBUF: 346 case SO_RCVBUF: 347 ret = socketGetOption(opt, null); 348 return new Integer(ret); 349 case IP_TOS: 350 try { 351 ret = socketGetOption(opt, null); 352 if (ret == -1) { // ipv6 tos 353 return trafficClass; 354 } else { 355 return ret; 356 } 357 } catch (SocketException se) { 358 // TODO - should make better effort to read TOS or TCLASS 359 return trafficClass; // ipv6 tos 360 } 361 case SO_KEEPALIVE: 362 ret = socketGetOption(opt, null); 363 return Boolean.valueOf(ret != -1); 364 // should never get here 365 default: 366 return null; 367 } 368 */ 369 return socketGetOption(opt); 370 // END Android-changed: Logic dealing with value type moved to socketGetOption. 371 } 372 373 /** 374 * The workhorse of the connection operation. Tries several times to 375 * establish a connection to the given <host, port>. If unsuccessful, 376 * throws an IOException indicating what went wrong. 377 */ 378 doConnect(InetAddress address, int port, int timeout)379 synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { 380 synchronized (fdLock) { 381 if (!closePending && (socket == null || !socket.isBound())) { 382 NetHooks.beforeTcpConnect(fd, address, port); 383 } 384 } 385 try { 386 acquireFD(); 387 try { 388 // Android-added: BlockGuard 389 BlockGuard.getThreadPolicy().onNetwork(); 390 socketConnect(address, port, timeout); 391 /* socket may have been closed during poll/select */ 392 synchronized (fdLock) { 393 if (closePending) { 394 throw new SocketException ("Socket closed"); 395 } 396 } 397 // If we have a ref. to the Socket, then sets the flags 398 // created, bound & connected to true. 399 // This is normally done in Socket.connect() but some 400 // subclasses of Socket may call impl.connect() directly! 401 if (socket != null) { 402 socket.setBound(); 403 socket.setConnected(); 404 } 405 } finally { 406 releaseFD(); 407 } 408 } catch (IOException e) { 409 close(); 410 throw e; 411 } 412 } 413 414 /** 415 * Binds the socket to the specified address of the specified local port. 416 * @param address the address 417 * @param lport the port 418 */ bind(InetAddress address, int lport)419 protected synchronized void bind(InetAddress address, int lport) 420 throws IOException 421 { 422 synchronized (fdLock) { 423 if (!closePending && (socket == null || !socket.isBound())) { 424 NetHooks.beforeTcpBind(fd, address, lport); 425 } 426 } 427 socketBind(address, lport); 428 if (socket != null) 429 socket.setBound(); 430 if (serverSocket != null) 431 serverSocket.setBound(); 432 } 433 434 /** 435 * Listens, for a specified amount of time, for connections. 436 * @param count the amount of time to listen for connections 437 */ listen(int count)438 protected synchronized void listen(int count) throws IOException { 439 socketListen(count); 440 } 441 442 /** 443 * Accepts connections. 444 * @param s the connection 445 */ accept(SocketImpl s)446 protected void accept(SocketImpl s) throws IOException { 447 acquireFD(); 448 try { 449 // Android-added: BlockGuard 450 BlockGuard.getThreadPolicy().onNetwork(); 451 socketAccept(s); 452 } finally { 453 releaseFD(); 454 } 455 } 456 457 /** 458 * Gets an InputStream for this socket. 459 */ getInputStream()460 protected synchronized InputStream getInputStream() throws IOException { 461 synchronized (fdLock) { 462 if (isClosedOrPending()) 463 throw new IOException("Socket Closed"); 464 if (shut_rd) 465 throw new IOException("Socket input is shutdown"); 466 if (socketInputStream == null) 467 socketInputStream = new SocketInputStream(this); 468 } 469 return socketInputStream; 470 } 471 setInputStream(SocketInputStream in)472 void setInputStream(SocketInputStream in) { 473 socketInputStream = in; 474 } 475 476 /** 477 * Gets an OutputStream for this socket. 478 */ getOutputStream()479 protected synchronized OutputStream getOutputStream() throws IOException { 480 synchronized (fdLock) { 481 if (isClosedOrPending()) 482 throw new IOException("Socket Closed"); 483 if (shut_wr) 484 throw new IOException("Socket output is shutdown"); 485 if (socketOutputStream == null) 486 socketOutputStream = new SocketOutputStream(this); 487 } 488 return socketOutputStream; 489 } 490 491 // Android-removed: this.fd is maintained by the concrete implementation. 492 /* 493 void setFileDescriptor(FileDescriptor fd) { 494 this.fd = fd; 495 } 496 */ 497 setAddress(InetAddress address)498 void setAddress(InetAddress address) { 499 this.address = address; 500 } 501 setPort(int port)502 void setPort(int port) { 503 this.port = port; 504 } 505 setLocalPort(int localport)506 void setLocalPort(int localport) { 507 this.localport = localport; 508 } 509 510 /** 511 * Returns the number of bytes that can be read without blocking. 512 */ available()513 protected synchronized int available() throws IOException { 514 if (isClosedOrPending()) { 515 throw new IOException("Stream closed."); 516 } 517 518 /* 519 * If connection has been reset or shut down for input, then return 0 520 * to indicate there are no buffered bytes. 521 */ 522 if (isConnectionReset() || shut_rd) { 523 return 0; 524 } 525 526 /* 527 * If no bytes available and we were previously notified 528 * of a connection reset then we move to the reset state. 529 * 530 * If are notified of a connection reset then check 531 * again if there are bytes buffered on the socket. 532 */ 533 int n = 0; 534 try { 535 n = socketAvailable(); 536 if (n == 0 && isConnectionResetPending()) { 537 setConnectionReset(); 538 } 539 } catch (ConnectionResetException exc1) { 540 setConnectionResetPending(); 541 try { 542 n = socketAvailable(); 543 if (n == 0) { 544 setConnectionReset(); 545 } 546 } catch (ConnectionResetException exc2) { 547 } 548 } 549 return n; 550 } 551 552 /** 553 * Closes the socket. 554 */ close()555 protected void close() throws IOException { 556 synchronized(fdLock) { 557 if (fd != null && fd.valid()) { 558 if (!stream) { 559 ResourceManager.afterUdpClose(); 560 } 561 // Android-changed: 562 // Socket should be untagged before the preclose. After preclose, 563 // socket will dup2-ed to marker_fd, therefore, it won't describe the same file. 564 // If closingPending is true, then the socket has been preclosed. 565 // 566 // Also, close the CloseGuard when the #close is called. 567 if (!closePending) { 568 closePending = true; 569 guard.close(); 570 571 if (fdUseCount == 0) { 572 /* 573 * We close the FileDescriptor in two-steps - first the 574 * "pre-close" which closes the socket but doesn't 575 * release the underlying file descriptor. This operation 576 * may be lengthy due to untransmitted data and a long 577 * linger interval. Once the pre-close is done we do the 578 * actual socket to release the fd. 579 */ 580 try { 581 socketPreClose(); 582 } finally { 583 socketClose(); 584 } 585 // Android-changed(http://b/26470377): Some Android code doesn't expect file 586 // descriptor to be null. socketClose invalidates the fd by closing the fd. 587 // fd = null; 588 return; 589 } else { 590 /* 591 * If a thread has acquired the fd and a close 592 * isn't pending then use a deferred close. 593 * Also decrement fdUseCount to signal the last 594 * thread that releases the fd to close it. 595 */ 596 fdUseCount--; 597 socketPreClose(); 598 } 599 } 600 } 601 } 602 } 603 reset()604 void reset() throws IOException { 605 if (fd != null && fd.valid()) { 606 socketClose(); 607 // Android-changed: Notified the CloseGuard object as the fd has been released. 608 guard.close(); 609 } 610 // Android-removed: b/26470377 Represent closed sockets with invalid fd, not null. 611 // fd = null; 612 super.reset(); 613 } 614 615 616 /** 617 * Shutdown read-half of the socket connection; 618 */ shutdownInput()619 protected void shutdownInput() throws IOException { 620 // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null. 621 if (fd != null && fd.valid()) { 622 socketShutdown(SHUT_RD); 623 if (socketInputStream != null) { 624 socketInputStream.setEOF(true); 625 } 626 shut_rd = true; 627 } 628 } 629 630 /** 631 * Shutdown write-half of the socket connection; 632 */ shutdownOutput()633 protected void shutdownOutput() throws IOException { 634 // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null. 635 if (fd != null && fd.valid()) { 636 socketShutdown(SHUT_WR); 637 shut_wr = true; 638 } 639 } 640 supportsUrgentData()641 protected boolean supportsUrgentData () { 642 return true; 643 } 644 sendUrgentData(int data)645 protected void sendUrgentData (int data) throws IOException { 646 // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null. 647 if (fd == null || !fd.valid()) { 648 throw new IOException("Socket Closed"); 649 } 650 socketSendUrgentData (data); 651 } 652 653 /** 654 * Cleans up if the user forgets to close it. 655 */ finalize()656 protected void finalize() throws IOException { 657 // Android-added: CloseGuard 658 if (guard != null) { 659 guard.warnIfOpen(); 660 } 661 662 close(); 663 } 664 665 /* 666 * "Acquires" and returns the FileDescriptor for this impl 667 * 668 * A corresponding releaseFD is required to "release" the 669 * FileDescriptor. 670 */ acquireFD()671 FileDescriptor acquireFD() { 672 synchronized (fdLock) { 673 fdUseCount++; 674 return fd; 675 } 676 } 677 678 /* 679 * "Release" the FileDescriptor for this impl. 680 * 681 * If the use count goes to -1 then the socket is closed. 682 */ releaseFD()683 void releaseFD() { 684 synchronized (fdLock) { 685 fdUseCount--; 686 if (fdUseCount == -1) { 687 if (fd != null) { 688 try { 689 socketClose(); 690 } catch (IOException e) { 691 // Android-removed: b/26470377 Some Android code doesn't expect file 692 // descriptor to be null. socketClose invalidates the fd by closing the fd. 693 // } finally { 694 // fd = null; 695 } 696 } 697 } 698 } 699 } 700 isConnectionReset()701 public boolean isConnectionReset() { 702 synchronized (resetLock) { 703 return (resetState == CONNECTION_RESET); 704 } 705 } 706 isConnectionResetPending()707 public boolean isConnectionResetPending() { 708 synchronized (resetLock) { 709 return (resetState == CONNECTION_RESET_PENDING); 710 } 711 } 712 setConnectionReset()713 public void setConnectionReset() { 714 synchronized (resetLock) { 715 resetState = CONNECTION_RESET; 716 } 717 } 718 setConnectionResetPending()719 public void setConnectionResetPending() { 720 synchronized (resetLock) { 721 if (resetState == CONNECTION_NOT_RESET) { 722 resetState = CONNECTION_RESET_PENDING; 723 } 724 } 725 726 } 727 728 /* 729 * Return true if already closed or close is pending 730 */ isClosedOrPending()731 public boolean isClosedOrPending() { 732 /* 733 * Lock on fdLock to ensure that we wait if a 734 * close is in progress. 735 */ 736 synchronized (fdLock) { 737 // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null. 738 if (closePending || (fd == null) || !fd.valid()) { 739 return true; 740 } else { 741 return false; 742 } 743 } 744 } 745 746 /* 747 * Return the current value of SO_TIMEOUT 748 */ getTimeout()749 public int getTimeout() { 750 return timeout; 751 } 752 753 /* 754 * "Pre-close" a socket by dup'ing the file descriptor - this enables 755 * the socket to be closed without releasing the file descriptor. 756 */ socketPreClose()757 private void socketPreClose() throws IOException { 758 socketClose0(true); 759 } 760 761 /* 762 * Close the socket (and release the file descriptor). 763 */ socketClose()764 protected void socketClose() throws IOException { 765 socketClose0(false); 766 } 767 socketCreate(boolean isServer)768 abstract void socketCreate(boolean isServer) throws IOException; socketConnect(InetAddress address, int port, int timeout)769 abstract void socketConnect(InetAddress address, int port, int timeout) 770 throws IOException; socketBind(InetAddress address, int port)771 abstract void socketBind(InetAddress address, int port) 772 throws IOException; socketListen(int count)773 abstract void socketListen(int count) 774 throws IOException; socketAccept(SocketImpl s)775 abstract void socketAccept(SocketImpl s) 776 throws IOException; socketAvailable()777 abstract int socketAvailable() 778 throws IOException; socketClose0(boolean useDeferredClose)779 abstract void socketClose0(boolean useDeferredClose) 780 throws IOException; socketShutdown(int howto)781 abstract void socketShutdown(int howto) 782 throws IOException; 783 784 // Android-changed: Method signature changed, socket{Get,Set}Option work directly with Object 785 // values. socketSetOption(int cmd, Object value)786 abstract void socketSetOption(int cmd, Object value) throws SocketException; socketGetOption(int opt)787 abstract Object socketGetOption(int opt) throws SocketException; 788 socketSendUrgentData(int data)789 abstract void socketSendUrgentData(int data) 790 throws IOException; 791 792 public final static int SHUT_RD = 0; 793 public final static int SHUT_WR = 1; 794 } 795