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