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