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 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 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<Void>() { 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 ret = socketGetOption(opt, null); 316 if (ret == -1) { // ipv6 tos 317 return trafficClass; 318 } else { 319 return ret; 320 } 321 case SO_KEEPALIVE: 322 ret = socketGetOption(opt, null); 323 return Boolean.valueOf(ret != -1); 324 // should never get here 325 default: 326 return null; 327 } 328 } 329 330 /** 331 * The workhorse of the connection operation. Tries several times to 332 * establish a connection to the given <host, port>. If unsuccessful, 333 * throws an IOException indicating what went wrong. 334 */ 335 336 synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { 337 synchronized (fdLock) { 338 if (!closePending && (socket == null || !socket.isBound())) { 339 NetHooks.beforeTcpConnect(fd, address, port); 340 } 341 } 342 try { 343 acquireFD(); 344 try { 345 socketConnect(address, port, timeout); 346 /* socket may have been closed during poll/select */ 347 synchronized (fdLock) { 348 if (closePending) { 349 throw new SocketException ("Socket closed"); 350 } 351 } 352 // If we have a ref. to the Socket, then sets the flags 353 // created, bound & connected to true. 354 // This is normally done in Socket.connect() but some 355 // subclasses of Socket may call impl.connect() directly! 356 if (socket != null) { 357 socket.setBound(); 358 socket.setConnected(); 359 } 360 } finally { 361 releaseFD(); 362 } 363 } catch (IOException e) { 364 close(); 365 throw e; 366 } 367 } 368 369 /** 370 * Binds the socket to the specified address of the specified local port. 371 * @param address the address 372 * @param lport the port 373 */ 374 protected synchronized void bind(InetAddress address, int lport) 375 throws IOException 376 { 377 synchronized (fdLock) { 378 if (!closePending && (socket == null || !socket.isBound())) { 379 NetHooks.beforeTcpBind(fd, address, lport); 380 } 381 } 382 socketBind(address, lport); 383 if (socket != null) 384 socket.setBound(); 385 if (serverSocket != null) 386 serverSocket.setBound(); 387 } 388 389 /** 390 * Listens, for a specified amount of time, for connections. 391 * @param count the amount of time to listen for connections 392 */ 393 protected synchronized void listen(int count) throws IOException { 394 socketListen(count); 395 } 396 397 /** 398 * Accepts connections. 399 * @param s the connection 400 */ 401 protected void accept(SocketImpl s) throws IOException { 402 acquireFD(); 403 try { 404 socketAccept(s); 405 } finally { 406 releaseFD(); 407 } 408 } 409 410 /** 411 * Gets an InputStream for this socket. 412 */ 413 protected synchronized InputStream getInputStream() throws IOException { 414 synchronized (fdLock) { 415 if (isClosedOrPending()) 416 throw new IOException("Socket Closed"); 417 if (shut_rd) 418 throw new IOException("Socket input is shutdown"); 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 synchronized (fdLock) { 434 if (isClosedOrPending()) 435 throw new IOException("Socket Closed"); 436 if (shut_wr) 437 throw new IOException("Socket output is shutdown"); 438 if (socketOutputStream == null) 439 socketOutputStream = new SocketOutputStream(this); 440 } 441 return socketOutputStream; 442 } 443 444 void setFileDescriptor(FileDescriptor fd) { 445 this.fd = fd; 446 } 447 448 void setAddress(InetAddress address) { 449 this.address = address; 450 } 451 452 void setPort(int port) { 453 this.port = port; 454 } 455 456 void setLocalPort(int localport) { 457 this.localport = localport; 458 } 459 460 /** 461 * Returns the number of bytes that can be read without blocking. 462 */ 463 protected synchronized int available() throws IOException { 464 if (isClosedOrPending()) { 465 throw new IOException("Stream closed."); 466 } 467 468 /* 469 * If connection has been reset or shut down for input, then return 0 470 * to indicate there are no buffered bytes. 471 */ 472 if (isConnectionReset() || shut_rd) { 473 return 0; 474 } 475 476 /* 477 * If no bytes available and we were previously notified 478 * of a connection reset then we move to the reset state. 479 * 480 * If are notified of a connection reset then check 481 * again if there are bytes buffered on the socket. 482 */ 483 int n = 0; 484 try { 485 n = socketAvailable(); 486 if (n == 0 && isConnectionResetPending()) { 487 setConnectionReset(); 488 } 489 } catch (ConnectionResetException exc1) { 490 setConnectionResetPending(); 491 try { 492 n = socketAvailable(); 493 if (n == 0) { 494 setConnectionReset(); 495 } 496 } catch (ConnectionResetException exc2) { 497 } 498 } 499 return n; 500 } 501 502 /** 503 * Closes the socket. 504 */ 505 protected void close() throws IOException { 506 synchronized(fdLock) { 507 if (fd != null) { 508 if (!stream) { 509 ResourceManager.afterUdpClose(); 510 } 511 if (fdUseCount == 0) { 512 if (closePending) { 513 return; 514 } 515 closePending = true; 516 /* 517 * We close the FileDescriptor in two-steps - first the 518 * "pre-close" which closes the socket but doesn't 519 * release the underlying file descriptor. This operation 520 * may be lengthy due to untransmitted data and a long 521 * linger interval. Once the pre-close is done we do the 522 * actual socket to release the fd. 523 */ 524 try { 525 socketPreClose(); 526 } finally { 527 socketClose(); 528 } 529 fd = null; 530 return; 531 } else { 532 /* 533 * If a thread has acquired the fd and a close 534 * isn't pending then use a deferred close. 535 * Also decrement fdUseCount to signal the last 536 * thread that releases the fd to close it. 537 */ 538 if (!closePending) { 539 closePending = true; 540 fdUseCount--; 541 socketPreClose(); 542 } 543 } 544 } 545 } 546 } 547 548 void reset() throws IOException { 549 if (fd != null) { 550 socketClose(); 551 } 552 fd = null; 553 super.reset(); 554 } 555 556 557 /** 558 * Shutdown read-half of the socket connection; 559 */ 560 protected void shutdownInput() throws IOException { 561 if (fd != null) { 562 socketShutdown(SHUT_RD); 563 if (socketInputStream != null) { 564 socketInputStream.setEOF(true); 565 } 566 shut_rd = true; 567 } 568 } 569 570 /** 571 * Shutdown write-half of the socket connection; 572 */ 573 protected void shutdownOutput() throws IOException { 574 if (fd != null) { 575 socketShutdown(SHUT_WR); 576 shut_wr = true; 577 } 578 } 579 580 protected boolean supportsUrgentData () { 581 return true; 582 } 583 584 protected void sendUrgentData (int data) throws IOException { 585 if (fd == null) { 586 throw new IOException("Socket Closed"); 587 } 588 socketSendUrgentData (data); 589 } 590 591 /** 592 * Cleans up if the user forgets to close it. 593 */ 594 protected void finalize() throws IOException { 595 close(); 596 } 597 598 /* 599 * "Acquires" and returns the FileDescriptor for this impl 600 * 601 * A corresponding releaseFD is required to "release" the 602 * FileDescriptor. 603 */ 604 FileDescriptor acquireFD() { 605 synchronized (fdLock) { 606 fdUseCount++; 607 return fd; 608 } 609 } 610 611 /* 612 * "Release" the FileDescriptor for this impl. 613 * 614 * If the use count goes to -1 then the socket is closed. 615 */ 616 void releaseFD() { 617 synchronized (fdLock) { 618 fdUseCount--; 619 if (fdUseCount == -1) { 620 if (fd != null) { 621 try { 622 socketClose(); 623 } catch (IOException e) { 624 } finally { 625 fd = null; 626 } 627 } 628 } 629 } 630 } 631 632 public boolean isConnectionReset() { 633 synchronized (resetLock) { 634 return (resetState == CONNECTION_RESET); 635 } 636 } 637 638 public boolean isConnectionResetPending() { 639 synchronized (resetLock) { 640 return (resetState == CONNECTION_RESET_PENDING); 641 } 642 } 643 644 public void setConnectionReset() { 645 synchronized (resetLock) { 646 resetState = CONNECTION_RESET; 647 } 648 } 649 650 public void setConnectionResetPending() { 651 synchronized (resetLock) { 652 if (resetState == CONNECTION_NOT_RESET) { 653 resetState = CONNECTION_RESET_PENDING; 654 } 655 } 656 657 } 658 659 /* 660 * Return true if already closed or close is pending 661 */ 662 public boolean isClosedOrPending() { 663 /* 664 * Lock on fdLock to ensure that we wait if a 665 * close is in progress. 666 */ 667 synchronized (fdLock) { 668 if (closePending || (fd == null)) { 669 return true; 670 } else { 671 return false; 672 } 673 } 674 } 675 676 /* 677 * Return the current value of SO_TIMEOUT 678 */ 679 public int getTimeout() { 680 return timeout; 681 } 682 683 /* 684 * "Pre-close" a socket by dup'ing the file descriptor - this enables 685 * the socket to be closed without releasing the file descriptor. 686 */ 687 private void socketPreClose() throws IOException { 688 socketClose0(true); 689 } 690 691 /* 692 * Close the socket (and release the file descriptor). 693 */ 694 protected void socketClose() throws IOException { 695 socketClose0(false); 696 } 697 698 abstract void socketCreate(boolean isServer) throws IOException; 699 abstract void socketConnect(InetAddress address, int port, int timeout) 700 throws IOException; 701 abstract void socketBind(InetAddress address, int port) 702 throws IOException; 703 abstract void socketListen(int count) 704 throws IOException; 705 abstract void socketAccept(SocketImpl s) 706 throws IOException; 707 abstract int socketAvailable() 708 throws IOException; 709 abstract void socketClose0(boolean useDeferredClose) 710 throws IOException; 711 abstract void socketShutdown(int howto) 712 throws IOException; 713 abstract void socketSetOption(int cmd, boolean on, Object value) 714 throws SocketException; 715 abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException; 716 abstract void socketSendUrgentData(int data) 717 throws IOException; 718 719 public final static int SHUT_RD = 0; 720 public final static int SHUT_WR = 1; 721 }