// Path: src/main/java/com/yammer/httptunnel/state/BindState.java
// public enum BindState {
// 	/**
// 	 * The channel is currently not bound to any address.
// 	 */
// 	UNBOUND,
// 
// 	/**
// 	 * The channel is currently in the process of binding to a local address.
// 	 */
// 	BINDING,
// 
// 	/**
// 	 * The channel is currently bound to a local address.
// 	 */
// 	BOUND,
// 
// 	/**
// 	 * The channel is currently in the process of unbinding from a local
// 	 * address.
// 	 */
// 	UNBINDING;
// }
// 
// Path: src/main/java/com/yammer/httptunnel/util/TunnelIdGenerator.java
// public interface TunnelIdGenerator {
// 
// 	/**
// 	 * Generates the next tunnel ID to be used, which must be unique (i.e.
// 	 * ensure with high probability that it will not clash with an existing
// 	 * tunnel ID). This method must be thread safe, and preferably lock free.
// 	 */
// 	public String generateId();
// }


import java.net.InetSocketAddress;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.jboss.netty.channel.AbstractServerChannel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineException;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelSink;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.socket.ServerSocketChannel;
import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import com.yammer.httptunnel.state.BindState;
import com.yammer.httptunnel.util.TunnelIdGenerator;
			unbindFuture.setSuccess();
			return unbindFuture;
		}

		final ChannelFutureListener unbindListener = new ChannelFutureListener() {
			@Override
			public void operationComplete(ChannelFuture future) throws Exception {
				if (future.isSuccess()) {
					bindState.set(BindState.UNBOUND);
					Channels.fireChannelUnbound(HttpTunnelServerChannel.this);

					if (unbindFuture != null)
						unbindFuture.setSuccess();
				}
				else {
					bindState.set(BindState.UNBOUND);
					Channels.fireExceptionCaught(HttpTunnelServerChannel.this, future.getCause());

					if (unbindFuture != null)
						unbindFuture.setFailure(future.getCause());
				}
			}
		};

		realChannel.unbind().addListener(unbindListener);

		return unbindFuture;
	}

	public HttpTunnelAcceptedChannel createTunnel(InetSocketAddress remoteAddress) {
// Path: src/main/java/com/yammer/httptunnel/state/BindState.java
// public enum BindState {
// 	/**
// 	 * The channel is currently not bound to any address.
// 	 */
// 	UNBOUND,
// 
// 	/**
// 	 * The channel is currently in the process of binding to a local address.
// 	 */
// 	BINDING,
// 
// 	/**
// 	 * The channel is currently bound to a local address.
// 	 */
// 	BOUND,
// 
// 	/**
// 	 * The channel is currently in the process of unbinding from a local
// 	 * address.
// 	 */
// 	UNBINDING;
// }
// 
// Path: src/main/java/com/yammer/httptunnel/util/TunnelIdGenerator.java
// public interface TunnelIdGenerator {
// 
// 	/**
// 	 * Generates the next tunnel ID to be used, which must be unique (i.e.
// 	 * ensure with high probability that it will not clash with an existing
// 	 * tunnel ID). This method must be thread safe, and preferably lock free.
// 	 */
// 	public String generateId();
// }


// Path: src/main/java/com/yammer/httptunnel/server/HttpTunnelServerChannel.java
import java.net.InetSocketAddress;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.jboss.netty.channel.AbstractServerChannel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineException;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelSink;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.socket.ServerSocketChannel;
import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import com.yammer.httptunnel.state.BindState;
import com.yammer.httptunnel.util.TunnelIdGenerator;

			unbindFuture.setSuccess();
			return unbindFuture;
		}

		final ChannelFutureListener unbindListener = new ChannelFutureListener() {
			@Override
			public void operationComplete(ChannelFuture future) throws Exception {
				if (future.isSuccess()) {
					bindState.set(BindState.UNBOUND);
					Channels.fireChannelUnbound(HttpTunnelServerChannel.this);

					if (unbindFuture != null)
						unbindFuture.setSuccess();
				}
				else {
					bindState.set(BindState.UNBOUND);
					Channels.fireExceptionCaught(HttpTunnelServerChannel.this, future.getCause());

					if (unbindFuture != null)
						unbindFuture.setFailure(future.getCause());
				}
			}
		};

		realChannel.unbind().addListener(unbindListener);

		return unbindFuture;
	}

	public HttpTunnelAcceptedChannel createTunnel(InetSocketAddress remoteAddress) {
		final TunnelIdGenerator tunnelIdGenerator = config.getTunnelIdGenerator();