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