All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.netty.channel.socket.http.HttpTunnelAcceptedChannelSink Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2011 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.channel.socket.http;

import java.util.concurrent.atomic.AtomicBoolean;

import io.netty.buffer.ChannelBuffer;
import io.netty.channel.AbstractChannelSink;
import io.netty.channel.Channel;
import io.netty.channel.ChannelEvent;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelStateEvent;
import io.netty.channel.Channels;
import io.netty.channel.MessageEvent;

/**
 * Sink for the server end of an http tunnel. Data sent down through the server end is dispatched
 * from here to the ServerMessageSwitch, which queues the data awaiting a poll request from the
 * client end of the tunnel.
 */
class HttpTunnelAcceptedChannelSink extends AbstractChannelSink {

    final SaturationManager saturationManager;

    private final ServerMessageSwitchDownstreamInterface messageSwitch;

    private final String tunnelId;

    private final AtomicBoolean active = new AtomicBoolean(false);

    private final HttpTunnelAcceptedChannelConfig config;

    public HttpTunnelAcceptedChannelSink(
            ServerMessageSwitchDownstreamInterface messageSwitch,
            String tunnelId, HttpTunnelAcceptedChannelConfig config) {
        this.messageSwitch = messageSwitch;
        this.tunnelId = tunnelId;
        this.config = config;
        saturationManager =
                new SaturationManager(config.getWriteBufferLowWaterMark(),
                        config.getWriteBufferHighWaterMark());
    }

    @Override
    public void eventSunk(ChannelPipeline pipeline, ChannelEvent e)
            throws Exception {
        if (e instanceof MessageEvent) {
            handleMessageEvent((MessageEvent) e);
        } else if (e instanceof ChannelStateEvent) {
            handleStateEvent((ChannelStateEvent) e);
        }
    }

    private void handleMessageEvent(MessageEvent ev) {
        if (!(ev.getMessage() instanceof ChannelBuffer)) {
            throw new IllegalArgumentException(
                    "Attempt to send data which is not a ChannelBuffer:" +
                            ev.getMessage());
        }

        final HttpTunnelAcceptedChannelReceiver channel =
                (HttpTunnelAcceptedChannelReceiver) ev.getChannel();
        final ChannelBuffer message = (ChannelBuffer) ev.getMessage();
        final int messageSize = message.readableBytes();
        final ChannelFuture future = ev.getFuture();

        saturationManager.updateThresholds(config.getWriteBufferLowWaterMark(),
                config.getWriteBufferHighWaterMark());
        channel.updateInterestOps(saturationManager
                .queueSizeChanged(messageSize));
        future.addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture future)
                    throws Exception {
                channel.updateInterestOps(saturationManager
                        .queueSizeChanged(-messageSize));
            }
        });
        messageSwitch.routeOutboundData(tunnelId, message, future);
    }

    private void handleStateEvent(ChannelStateEvent ev) {
        /* TODO: as any of disconnect, unbind or close destroys a server
           channel, should we fire all three events always? */
        Channel owner = ev.getChannel();
        switch (ev.getState()) {
        case OPEN:
            if (Boolean.FALSE.equals(ev.getValue())) {
                messageSwitch.serverCloseTunnel(tunnelId);
                active.set(false);
                Channels.fireChannelClosed(owner);
            }
            break;
        case BOUND:
            if (ev.getValue() == null) {
                messageSwitch.serverCloseTunnel(tunnelId);
                active.set(false);
                Channels.fireChannelUnbound(owner);
            }
        case CONNECTED:
            if (ev.getValue() == null) {
                messageSwitch.serverCloseTunnel(tunnelId);
                active.set(false);
                Channels.fireChannelDisconnected(owner);
            }
        }
    }

    public boolean isActive() {
        return active.get();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy