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 }