@Override <A> Future<Void> implConnect( SocketAddress remote, A attachment, CompletionHandler<Void, ? super A> handler) { if (!isOpen()) { Throwable exc = new ClosedChannelException(); if (handler == null) return CompletedFuture.withFailure(exc); Invoker.invoke(this, handler, attachment, null, exc); return null; } InetSocketAddress isa = Net.checkAddress(remote); // permission check SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); // check and update state // ConnectEx requires the socket to be bound to a local address IOException bindException = null; synchronized (stateLock) { if (state == ST_CONNECTED) throw new AlreadyConnectedException(); if (state == ST_PENDING) throw new ConnectionPendingException(); if (localAddress == null) { try { bind(new InetSocketAddress(0)); } catch (IOException x) { bindException = x; } } if (bindException == null) state = ST_PENDING; } // handle bind failure if (bindException != null) { try { close(); } catch (IOException ignore) { } if (handler == null) return CompletedFuture.withFailure(bindException); Invoker.invoke(this, handler, attachment, null, bindException); return null; } // setup task PendingFuture<Void, A> result = new PendingFuture<Void, A>(this, handler, attachment); ConnectTask task = new ConnectTask<A>(isa, result); result.setContext(task); // initiate I/O if (Iocp.supportsThreadAgnosticIo()) { task.run(); } else { Invoker.invokeOnThreadInThreadPool(this, task); } return result; }
/** Executed when the I/O has completed */ @Override @SuppressWarnings("unchecked") public void completed(int bytesTransferred, boolean canInvokeDirect) { if (bytesTransferred == 0) { bytesTransferred = -1; // EOF } else { updateBuffers(bytesTransferred); } // return direct buffer to cache if substituted releaseBuffers(); // release waiters if not already released by timeout synchronized (result) { if (result.isDone()) return; enableReading(); if (scatteringRead) { result.setResult((V) Long.valueOf(bytesTransferred)); } else { result.setResult((V) Integer.valueOf(bytesTransferred)); } } if (canInvokeDirect) { Invoker.invokeUnchecked(result); } else { Invoker.invoke(result); } }
/** Invoked by handler thread when connection established. */ @Override public void completed(int bytesTransferred, boolean canInvokeDirect) { Throwable exc = null; try { begin(); afterConnect(); result.setResult(null); } catch (Throwable x) { // channel is closed or unable to finish connect exc = x; } finally { end(); } // can't close channel while in begin/end block if (exc != null) { closeChannel(); result.setFailure(toIOException(exc)); } if (canInvokeDirect) { Invoker.invokeUnchecked(result); } else { Invoker.invoke(result); } }
/** Invoked by handler thread when failed to establish connection. */ @Override public void failed(int error, IOException x) { if (isOpen()) { closeChannel(); result.setFailure(x); } else { result.setFailure(new AsynchronousCloseException()); } Invoker.invoke(result); }
@Override @SuppressWarnings("unchecked") public void run() { long overlapped = 0L; boolean prepared = false; boolean pending = false; try { begin(); // substitute non-direct buffers prepareBuffers(); prepared = true; // get an OVERLAPPED structure (from the cache or allocate) overlapped = ioCache.add(result); // initiate read int n = read0(handle, numBufs, readBufferArray, overlapped); if (n == IOStatus.UNAVAILABLE) { // I/O is pending pending = true; return; } if (n == IOStatus.EOF) { // input shutdown enableReading(); if (scatteringRead) { result.setResult((V) Long.valueOf(-1L)); } else { result.setResult((V) Integer.valueOf(-1)); } } else { throw new InternalError("Read completed immediately"); } } catch (Throwable x) { // failed to initiate read // reset read flag before releasing waiters enableReading(); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); if (!(x instanceof IOException)) x = new IOException(x); result.setFailure(x); } finally { // release resources if I/O not pending if (!pending) { if (overlapped != 0L) ioCache.remove(overlapped); if (prepared) releaseBuffers(); } end(); } // invoke completion handler Invoker.invoke(result); }
/** Invoked if timeout expires before it is cancelled */ void timeout() { // synchronize on result as the I/O could complete/fail synchronized (result) { if (result.isDone()) return; // kill further writing before releasing waiters enableWriting(true); result.setFailure(new InterruptedByTimeoutException()); } // invoke handler without any locks Invoker.invoke(result); }
@Override // @SuppressWarnings("unchecked") public void run() { long overlapped = 0L; boolean prepared = false; boolean pending = false; boolean shutdown = false; try { begin(); // substitute non-direct buffers prepareBuffers(); prepared = true; // get an OVERLAPPED structure (from the cache or allocate) overlapped = ioCache.add(result); int n = write0(handle, numBufs, writeBufferArray, overlapped); if (n == IOStatus.UNAVAILABLE) { // I/O is pending pending = true; return; } if (n == IOStatus.EOF) { // special case for shutdown output shutdown = true; throw new ClosedChannelException(); } // write completed immediately throw new InternalError("Write completed immediately"); } catch (Throwable x) { // write failed. Enable writing before releasing waiters. enableWriting(); if (!shutdown && (x instanceof ClosedChannelException)) x = new AsynchronousCloseException(); if (!(x instanceof IOException)) x = new IOException(x); result.setFailure(x); } finally { // release resources if I/O not pending if (!pending) { if (overlapped != 0L) ioCache.remove(overlapped); if (prepared) releaseBuffers(); } end(); } // invoke completion handler Invoker.invoke(result); }
@Override public void failed(int error, IOException x) { // return direct buffer to cache if substituted releaseBuffers(); // release waiters if not already released by timeout if (!isOpen()) x = new AsynchronousCloseException(); synchronized (result) { if (result.isDone()) return; enableWriting(); result.setFailure(x); } Invoker.invoke(result); }
/** Task to initiate a connection. */ @Override public void run() { long overlapped = 0L; Throwable exc = null; try { begin(); // synchronize on result to allow this thread handle the case // where the connection is established immediately. synchronized (result) { overlapped = ioCache.add(result); // initiate the connection int n = connect0( handle, Net.isIPv6Available(), remote.getAddress(), remote.getPort(), overlapped); if (n == IOStatus.UNAVAILABLE) { // connection is pending return; } // connection established immediately afterConnect(); result.setResult(null); } } catch (Throwable x) { if (overlapped != 0L) ioCache.remove(overlapped); exc = x; } finally { end(); } if (exc != null) { closeChannel(); result.setFailure(toIOException(exc)); } Invoker.invoke(result); }