src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java
changeset 49141 ac95c7a76132
parent 49001 ce06058197a4
child 49142 4affaea00c05
equal deleted inserted replaced
49140:9ffbe8258541 49141:ac95c7a76132
   586         }
   586         }
   587     }
   587     }
   588 
   588 
   589     /**
   589     /**
   590      * Marks the beginning of a connect operation that might block.
   590      * Marks the beginning of a connect operation that might block.
   591      *
   591      * @param blocking true if configured blocking
       
   592      * @param isa the remote address
   592      * @throws ClosedChannelException if the channel is closed
   593      * @throws ClosedChannelException if the channel is closed
   593      * @throws AlreadyConnectedException if already connected
   594      * @throws AlreadyConnectedException if already connected
   594      * @throws ConnectionPendingException is a connection is pending
   595      * @throws ConnectionPendingException is a connection is pending
   595      */
   596      * @throws IOException if the pre-connect hook fails
   596     private void beginConnect(boolean blocking) throws ClosedChannelException {
   597      */
       
   598     private void beginConnect(boolean blocking, InetSocketAddress isa)
       
   599         throws IOException
       
   600     {
   597         if (blocking) {
   601         if (blocking) {
   598             // set hook for Thread.interrupt
   602             // set hook for Thread.interrupt
   599             begin();
   603             begin();
   600         }
   604         }
   601         synchronized (stateLock) {
   605         synchronized (stateLock) {
   602             ensureOpen();
   606             ensureOpen();
   603             if (state == ST_CONNECTED)
   607             if (state == ST_CONNECTED)
   604                 throw new AlreadyConnectedException();
   608                 throw new AlreadyConnectedException();
   605             if (state == ST_CONNECTIONPENDING)
   609             if (state == ST_CONNECTIONPENDING)
   606                 throw new ConnectionPendingException();
   610                 throw new ConnectionPendingException();
       
   611             assert state == ST_UNCONNECTED;
       
   612             state = ST_CONNECTIONPENDING;
       
   613 
       
   614             if (localAddress == null)
       
   615                 NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
       
   616             remoteAddress = isa;
       
   617 
   607             if (blocking)
   618             if (blocking)
   608                 readerThread = NativeThread.current();
   619                 readerThread = NativeThread.current();
   609         }
   620         }
   610     }
   621     }
   611 
   622 
   612     /**
   623     /**
   613      * Marks the end of a connect operation that may have blocked.
   624      * Marks the end of a connect operation that may have blocked.
   614      *
   625      *
   615      * @throws AsynchronousCloseException if the channel was closed due to this
   626      * @throws AsynchronousCloseException if the channel was closed due to this
   616      * thread being interrupted on a blocking connect operation.
   627      * thread being interrupted on a blocking connect operation.
       
   628      * @throws IOException if completed and unable to obtain the local address
   617      */
   629      */
   618     private void endConnect(boolean blocking, boolean completed)
   630     private void endConnect(boolean blocking, boolean completed)
   619         throws AsynchronousCloseException
   631         throws IOException
   620     {
   632     {
   621         endRead(blocking, completed);
   633         endRead(blocking, completed);
       
   634 
       
   635         if (completed) {
       
   636             synchronized (stateLock) {
       
   637                 if (state == ST_CONNECTIONPENDING) {
       
   638                     localAddress = Net.localAddress(fd);
       
   639                     state = ST_CONNECTED;
       
   640                 }
       
   641             }
       
   642         }
   622     }
   643     }
   623 
   644 
   624     @Override
   645     @Override
   625     public boolean connect(SocketAddress sa) throws IOException {
   646     public boolean connect(SocketAddress sa) throws IOException {
   626         InetSocketAddress isa = Net.checkAddress(sa);
   647         InetSocketAddress isa = Net.checkAddress(sa);
   627         SecurityManager sm = System.getSecurityManager();
   648         SecurityManager sm = System.getSecurityManager();
   628         if (sm != null)
   649         if (sm != null)
   629             sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
   650             sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
   630 
   651 
   631         readLock.lock();
   652         InetAddress ia = isa.getAddress();
       
   653         if (ia.isAnyLocalAddress())
       
   654             ia = InetAddress.getLocalHost();
       
   655 
   632         try {
   656         try {
   633             writeLock.lock();
   657             readLock.lock();
   634             try {
   658             try {
   635                 // notify before-connect hook
   659                 writeLock.lock();
   636                 synchronized (stateLock) {
   660                 try {
   637                     if (state == ST_UNCONNECTED && localAddress == null) {
   661                     int n = 0;
   638                         NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
   662                     boolean blocking = isBlocking();
       
   663                     try {
       
   664                         beginConnect(blocking, isa);
       
   665                         do {
       
   666                             n = Net.connect(fd, ia, isa.getPort());
       
   667                         } while (n == IOStatus.INTERRUPTED && isOpen());
       
   668                     } finally {
       
   669                         endConnect(blocking, (n > 0));
   639                     }
   670                     }
   640                 }
   671                     assert IOStatus.check(n);
   641 
   672                     return n > 0;
   642                 InetAddress ia = isa.getAddress();
   673                 } finally {
   643                 if (ia.isAnyLocalAddress())
   674                     writeLock.unlock();
   644                     ia = InetAddress.getLocalHost();
   675                 }
   645 
   676             } finally {
   646                 int n = 0;
   677                 readLock.unlock();
   647                 boolean blocking = isBlocking();
   678             }
   648                 try {
   679         } catch (IOException ioe) {
   649                     try {
   680             // connect failed, close the channel
   650                         beginConnect(blocking);
   681             close();
   651                         if (blocking) {
   682             throw ioe;
   652                             do {
       
   653                                 n = Net.connect(fd, ia, isa.getPort());
       
   654                             } while (n == IOStatus.INTERRUPTED && isOpen());
       
   655                         } else {
       
   656                             n = Net.connect(fd, ia, isa.getPort());
       
   657                         }
       
   658                     } finally {
       
   659                         endConnect(blocking, n > 0);
       
   660                     }
       
   661                 } catch (IOException x) {
       
   662                     // connect failed, close socket
       
   663                     close();
       
   664                     throw x;
       
   665                 }
       
   666 
       
   667                 // connection may be established
       
   668                 synchronized (stateLock) {
       
   669                     if (!isOpen())
       
   670                         throw new AsynchronousCloseException();
       
   671                     remoteAddress = isa;
       
   672                     if (n > 0) {
       
   673                         // connected established
       
   674                         localAddress = Net.localAddress(fd);
       
   675                         state = ST_CONNECTED;
       
   676                         return true;
       
   677                     } else {
       
   678                         // connection pending
       
   679                         assert !blocking;
       
   680                         state = ST_CONNECTIONPENDING;
       
   681                         return false;
       
   682                     }
       
   683                 }
       
   684             } finally {
       
   685                 writeLock.unlock();
       
   686             }
       
   687         } finally {
       
   688             readLock.unlock();
       
   689         }
   683         }
   690     }
   684     }
   691 
   685 
   692     /**
   686     /**
   693      * Marks the beginning of a finishConnect operation that might block.
   687      * Marks the beginning of a finishConnect operation that might block.
   712     /**
   706     /**
   713      * Marks the end of a finishConnect operation that may have blocked.
   707      * Marks the end of a finishConnect operation that may have blocked.
   714      *
   708      *
   715      * @throws AsynchronousCloseException if the channel was closed due to this
   709      * @throws AsynchronousCloseException if the channel was closed due to this
   716      * thread being interrupted on a blocking connect operation.
   710      * thread being interrupted on a blocking connect operation.
       
   711      * @throws IOException if completed and unable to obtain the local address
   717      */
   712      */
   718     private void endFinishConnect(boolean blocking, boolean completed)
   713     private void endFinishConnect(boolean blocking, boolean completed)
   719         throws AsynchronousCloseException
   714         throws IOException
   720     {
   715     {
   721         endRead(blocking, completed);
   716         endRead(blocking, completed);
       
   717 
       
   718         if (completed) {
       
   719             synchronized (stateLock) {
       
   720                 if (state == ST_CONNECTIONPENDING) {
       
   721                     localAddress = Net.localAddress(fd);
       
   722                     state = ST_CONNECTED;
       
   723                 }
       
   724             }
       
   725         }
   722     }
   726     }
   723 
   727 
   724     @Override
   728     @Override
   725     public boolean finishConnect() throws IOException {
   729     public boolean finishConnect() throws IOException {
   726         readLock.lock();
       
   727         try {
   730         try {
   728             writeLock.lock();
   731             readLock.lock();
   729             try {
   732             try {
   730                 // already connected?
   733                 writeLock.lock();
   731                 synchronized (stateLock) {
   734                 try {
   732                     if (state == ST_CONNECTED)
   735                     // no-op if already connected
       
   736                     if (isConnected())
   733                         return true;
   737                         return true;
   734                 }
   738 
   735 
   739                     boolean blocking = isBlocking();
   736                 int n = 0;
   740                     boolean connected = false;
   737                 boolean blocking = isBlocking();
       
   738                 try {
       
   739                     try {
   741                     try {
   740                         beginFinishConnect(blocking);
   742                         beginFinishConnect(blocking);
       
   743                         int n = 0;
   741                         if (blocking) {
   744                         if (blocking) {
   742                             do {
   745                             do {
   743                                 n = checkConnect(fd, true);
   746                                 n = checkConnect(fd, true);
   744                             } while (n == 0 || (n == IOStatus.INTERRUPTED) && isOpen());
   747                             } while ((n == 0 || n == IOStatus.INTERRUPTED) && isOpen());
   745                         } else {
   748                         } else {
   746                             n = checkConnect(fd, false);
   749                             n = checkConnect(fd, false);
   747                         }
   750                         }
       
   751                         connected = (n > 0);
   748                     } finally {
   752                     } finally {
   749                         endFinishConnect(blocking, n > 0);
   753                         endFinishConnect(blocking, connected);
   750                     }
   754                     }
   751                 } catch (IOException x) {
   755                     assert (blocking && connected) ^ !blocking;
   752                     close();
   756                     return connected;
   753                     throw x;
   757                 } finally {
   754                 }
   758                     writeLock.unlock();
   755 
   759                 }
   756                 // post finishConnect, connection may be established
   760             } finally {
   757                 synchronized (stateLock) {
   761                 readLock.unlock();
   758                     if (!isOpen())
   762             }
   759                         throw new AsynchronousCloseException();
   763         } catch (IOException ioe) {
   760                     if (n > 0) {
   764             // connect failed, close the channel
   761                         // connection established
   765             close();
   762                         localAddress = Net.localAddress(fd);
   766             throw ioe;
   763                         state = ST_CONNECTED;
       
   764                         return true;
       
   765                     } else {
       
   766                         // connection still pending
       
   767                         assert !blocking;
       
   768                         return false;
       
   769                     }
       
   770                 }
       
   771             } finally {
       
   772                 writeLock.unlock();
       
   773             }
       
   774         } finally {
       
   775             readLock.unlock();
       
   776         }
   767         }
   777     }
   768     }
   778 
   769 
   779     /**
   770     /**
   780      * Invoked by implCloseChannel to close the channel.
   771      * Invoked by implCloseChannel to close the channel.