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

Save This Page
Home » openjdk-7 » java » net » [javadoc | source]