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