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