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