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