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

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