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