Performs the closing handshake

@param channel
Channel
@param frame
Closing Frame that was received
@param promise
the {@link ChannelPromise} to be notified when the closing handshake is done
771496
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame, ChannelPromise promise) {
        if (channel == null) {
            throw new NullPointerException("channel");
        }
        return channel.writeAndFlush(frame, promise).addListener(ChannelFutureListener.CLOSE);
    }
944776
@Handler(channels = NetworkChannel.class)
    public void onClosed(Closed event, IOSubchannel netChannel) {
        LinkedIOSubchannel.downstreamChannel(this, netChannel,
            WebAppMsgChannel.class).ifPresent(appChannel -> {
                appChannel.handleClosed(event);
            });
    }
631486
private void socketClosedHandler() {
        // If the book-keeping has already been completed earlier, then
        // we should just bail.
        if (getReadyState() == ReadyState.CLOSED) {
            return;
        }
        
        // TODO: Determine whether channels need to be cleaned up
        if (this.channels.size() != 0) {
            // Iterate over the channels and close them.
            for (int i = 1; i <= this.channels.size(); i++) { // 1-based
                AmqpChannel channel = this.channels.get(i);
                AmqpFrame   f = new AmqpFrame();
                
                // Close the channel and ensure that the CLOSE event is
                // fired on the registered ChannelListener objects.
                f.setMethodName("closeChannel");
                f.setChannelId((short) i);
                channel.channelClosedHandler(this, "", f, "closeChannel");
            }
        }
        
        // Mark the readyState as CLOSED.
        readyState = ReadyState.CLOSED;

        // Fire the CLOSE event on the ConnectionListener(s) registered on
        // the AmqpClient object.
        fireOnClosed(new ConnectionEvent(this, Kind.CLOSE));
    }
281212
@Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        if (msg instanceof Http2DataFrame) {
            Http2DataFrame dataFrame = (Http2DataFrame) msg;
            encoder().writeData(ctx, dataFrame.stream().id(), dataFrame.content(),
                    dataFrame.padding(), dataFrame.isEndStream(), promise);
        } else if (msg instanceof Http2HeadersFrame) {
            writeHeadersFrame(ctx, (Http2HeadersFrame) msg, promise);
        } else if (msg instanceof Http2WindowUpdateFrame) {
            Http2WindowUpdateFrame frame = (Http2WindowUpdateFrame) msg;
            Http2FrameStream frameStream = frame.stream();
            // It is legit to send a WINDOW_UPDATE frame for the connection stream. The parent channel doesn't attempt
            // to set the Http2FrameStream so we assume if it is null the WINDOW_UPDATE is for the connection stream.
            try {
                if (frameStream == null) {
                    increaseInitialConnectionWindow(frame.windowSizeIncrement());
                } else {
                    consumeBytes(frameStream.id(), frame.windowSizeIncrement());
                }
                promise.setSuccess();
            } catch (Throwable t) {
                promise.setFailure(t);
            }
        } else if (msg instanceof Http2ResetFrame) {
            Http2ResetFrame rstFrame = (Http2ResetFrame) msg;
            encoder().writeRstStream(ctx, rstFrame.stream().id(), rstFrame.errorCode(), promise);
        } else if (msg instanceof Http2PingFrame) {
            Http2PingFrame frame = (Http2PingFrame) msg;
            encoder().writePing(ctx, frame.ack(), frame.content(), promise);
        } else if (msg instanceof Http2SettingsFrame) {
            encoder().writeSettings(ctx, ((Http2SettingsFrame) msg).settings(), promise);
        } else if (msg instanceof Http2SettingsAckFrame) {
            // In the event of manual SETTINGS ACK is is assumed the encoder will apply the earliest received but not
            // yet ACKed settings.
            encoder().writeSettingsAck(ctx, promise);
        } else if (msg instanceof Http2GoAwayFrame) {
            writeGoAwayFrame(ctx, (Http2GoAwayFrame) msg, promise);
        } else if (msg instanceof Http2UnknownFrame) {
            Http2UnknownFrame unknownFrame = (Http2UnknownFrame) msg;
            encoder().writeFrame(ctx, unknownFrame.frameType(), unknownFrame.stream().id(),
                    unknownFrame.flags(), unknownFrame.content(), promise);
        } else if (!(msg instanceof Http2Frame)) {
            ctx.write(msg, promise);
        } else {
            ReferenceCountUtil.release(msg);
            throw new UnsupportedMessageTypeException(msg);
        }
    }
656957
public void closeAfterFlushingPendingWrites(Channel channel, Event event)
	{
		if (channel.isConnected())
		{
			channel.write(event).addListener(ChannelFutureListener.CLOSE);
		}
		else
		{
			System.err.println("Unable to write the Event :" + event
					+ " to socket as channel is ot connected");
		}
	}
1340572
protected void handlePromise(Promise<T> promise) {
    if (!promise.isSuccess()) {
      this.setException(promise.cause());
    } else {
      this.response = promise.getNow();
      if (handlers != null) {
        for (IsSimplePromiseResponseHandler<T> h : handlers) {
          h.onResponse(this);
        }
      }
    }
  }
962679
protected void handleHttpRequest(final ChannelHandlerContext channelContext, final HttpRequest request) throws Exception {
        if (isWebSocketsUpgradeRequest( request )) {

            final Handshake handshake = findHandshake( request );

            if (handshake != null) {

                HttpResponse response = handshake.generateResponse( request );

                response.addHeader( Names.UPGRADE, Values.WEBSOCKET );
                response.addHeader( Names.CONNECTION, Values.UPGRADE );

                final ChannelPipeline pipeline = channelContext.getChannel().getPipeline();
                reconfigureUpstream( pipeline, handshake );

                Channel channel = channelContext.getChannel();
                ChannelFuture future = channel.write( response );
                future.addListener( new ChannelFutureListener() {
                    public void operationComplete(ChannelFuture future) throws Exception {
                        reconfigureDownstream( pipeline, handshake );
                        pipeline.replace( ServerHandshakeHandler.this, "websocket-disconnection-negotiator", new WebSocketDisconnectionNegotiator() );
                        forwardConnectEventUpstream( channelContext );
                        decodeHost( channelContext, request );
                        decodeSession( channelContext, request );
                    }
                } );

                return;
            }
        }

        // Send an error page otherwise.
        sendHttpResponse( channelContext, request, new DefaultHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN ) );
    }
1238803
@Override
	public Promise subscribe(String channel) {
		if (dispatcher != null) {
			try {
				dispatcher.subscribe(channel);
			} catch (Exception cause) {
				return Promise.reject(cause);
			}
		}
		return Promise.resolve();
	}
1371727
public void close(int statusCode, HandshakeResponse errResponse) {
        log.warn("Closing connection with status: {}", statusCode);
        // remove handshake flag
        session.removeAttribute(Constants.HANDSHAKE_COMPLETE);
        // clear the delay queue
        queue.clear();
        // send http error response
        session.write(errResponse);
        // whether to attempt a nice close or a forceful one
        if (WebSocketTransport.isNiceClose()) {
            // now send close packet with error code
            IoBuffer buf = IoBuffer.allocate(16);
            buf.setAutoExpand(true);
            // all errors except 403 will use 1002
            buf.putUnsigned((short) statusCode);
            try {
                if (statusCode == 1008) {
                    // if its a 403 forbidden
                    buf.put("Policy Violation".getBytes("UTF8"));
                } else {
                    buf.put("Protocol error".getBytes("UTF8"));
                }
            } catch (Exception e) {
                // shouldnt be any text encoding issues...
            }
            buf.flip();
            byte[] errBytes = new byte[buf.remaining()];
            buf.get(errBytes);
            // construct the packet
            Packet packet = Packet.build(errBytes, MessageType.CLOSE);
            WriteFuture writeFuture = session.write(packet);
            writeFuture.addListener(new IoFutureListener<WriteFuture>() {

                @Override
                public void operationComplete(WriteFuture future) {
                    if (future.isWritten()) {
                        log.debug("Close message written");
                        // only set on success for now to skip boolean check later
                        session.setAttribute(Constants.STATUS_CLOSE_WRITTEN, Boolean.TRUE);
                    }
                    future.removeListener(this);
                }

            });
            // adjust close routine to allow for flushing
            CloseFuture closeFuture = session.closeOnFlush();
            closeFuture.addListener(new IoFutureListener<CloseFuture>() {

                public void operationComplete(CloseFuture future) {
                    if (future.isClosed()) {
                        log.debug("Connection is closed");
                    } else {
                        log.debug("Connection is not yet closed");
                    }
                    future.removeListener(this);
                }

            });
        } else {
            // force close
            CloseFuture closeFuture = session.closeNow();
            closeFuture.addListener(new IoFutureListener<CloseFuture>() {

                public void operationComplete(CloseFuture future) {
                    if (future.isClosed()) {
                        log.debug("Connection is closed");
                    } else {
                        log.debug("Connection is not yet closed");
                    }
                    future.removeListener(this);
                }

            });
        }
        log.debug("Close complete");
    }
1333673
private ChannelFuture checkException(ChannelPromise promise) {
      Throwable t = lastException;
      if (t != null) {
        lastException = null;

        if (promise.isVoid()) {
            PlatformDependent.throwException(t);
        }

        return promise.setFailure(t);
      }

      return promise.setSuccess();
    }
615036
public void closeChannel(int channelId) {
        if (log.isTraceEnabled()) {
            log.trace("closeChannel: {}", channelId);
        }
        Channel chan = channels.remove(channelId);
        if (log.isTraceEnabled()) {
            log.trace("channel: {} for id: {}", chan, channelId);
            if (chan == null) {
                log.trace("Channels: {}", channels);
            }
        }
        /*
        ReceivedMessageTaskQueue queue = tasksByChannels.remove(channelId);
        if (queue != null) {
            if (isConnected()) {
                // if connected, drain and process the tasks queued-up
                log.debug("Processing remaining tasks at close for channel: {}", channelId);
                processTasksQueue(queue);
            }
            queue.removeAllTasks();
        } else if (log.isTraceEnabled()) {
            log.trace("No task queue for id: {}", channelId);
        }
        */
        chan = null;
    }
1359281
public void onCloseRemote(CloseInfo closeInfo) {
        if (LOG.isDebugEnabled())
            LOG.debug("onCloseRemote({})", closeInfo);
        ConnectionState event = null;
        synchronized (this) {
            if (this.state == ConnectionState.CLOSED) {
                // already closed
                return;
            }

            if (LOG.isDebugEnabled())
                LOG.debug("onCloseRemote(), input={}, output={}", inputAvailable, outputAvailable);

            this.closeInfo = closeInfo;

            // turn off further input
            inputAvailable = false;

            if (closeHandshakeSource == CloseHandshakeSource.NONE) {
                closeHandshakeSource = CloseHandshakeSource.REMOTE;
            }

            if (!outputAvailable) {
                LOG.debug("Close Handshake satisfied, disconnecting");
                cleanClose = true;
                state = ConnectionState.CLOSED;
                finalClose.compareAndSet(null, closeInfo);
                event = this.state;
            } else if (this.state == ConnectionState.OPEN) {
                // We are now entering CLOSING (or half-closed)
                this.state = ConnectionState.CLOSING;
                event = this.state;
            }
        }

        // Only notify on state change events
        if (event != null) {
            notifyStateListeners(event);
        }
    }
217765
@Override
    public void channelHandlerContext(ChannelHandlerContext ctx) throws Http2Exception {
        this.ctx = checkNotNull(ctx, "ctx");

        // Writing the pending bytes will not check writability change and instead a writability change notification
        // to be provided by an explicit call.
        channelWritabilityChanged();

        // Don't worry about cleaning up queued frames here if ctx is null. It is expected that all streams will be
        // closed and the queue cleanup will occur when the stream state transitions occur.

        // If any frames have been queued up, we should send them now that we have a channel context.
        if (isChannelWritable()) {
            writePendingBytes();
        }
    }
656945
@Override
    public synchronized void processClose(WebSocketChannel channel, int code, String reason) {
        nextHandler.processClose(channel, code, reason);        
    }
1168181
void onReadingThreadFinished(WebSocketFrame closeFrame)
    {
        synchronized (mThreadsLock)
        {
            mReadingThreadFinished = true;
            mServerCloseFrame = closeFrame;

            if (mWritingThreadFinished == false)
            {
                // Wait for the writing thread to finish.
                return;
            }
        }

        // Both the reading thread and the writing thread have finished.
        onThreadsFinished();
    }
925680
private void handleWebSocketHandshake(FullHttpRequest fullHttpRequest, ChannelHandlerContext ctx)
            throws WebSocketConnectorException {
        String extensionsHeader = fullHttpRequest.headers().getAsString(HttpHeaderNames.SEC_WEBSOCKET_EXTENSIONS);
        DefaultWebSocketHandshaker webSocketHandshaker =
                new DefaultWebSocketHandshaker(ctx, serverConnectorFuture, fullHttpRequest, fullHttpRequest.uri(),
                                               extensionsHeader != null);

        // Setting common properties to handshaker
        webSocketHandshaker.setHttpCarbonRequest(setupHttpCarbonRequest(fullHttpRequest, ctx));

        ctx.channel().config().setAutoRead(false);
        serverConnectorFuture.notifyWebSocketListener(webSocketHandshaker);
    }
776501
protected void handshakeFailure(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.warn("{} TLS handshake failed:", ctx.channel(), cause);
        ctx.close();
    }