Package com.sissi.server.netty.impl

Source Code of com.sissi.server.netty.impl.Socks5ProxyServerHandlerBuilder$ChannelHandlerContextCloseable

package com.sissi.server.netty.impl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.socks.SocksAddressType;
import io.netty.handler.codec.socks.SocksAuthScheme;
import io.netty.handler.codec.socks.SocksCmdRequest;
import io.netty.handler.codec.socks.SocksCmdResponse;
import io.netty.handler.codec.socks.SocksCmdStatus;
import io.netty.handler.codec.socks.SocksInitRequest;
import io.netty.handler.codec.socks.SocksInitResponse;
import io.netty.handler.codec.socks.SocksResponse;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

import java.io.Closeable;
import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sissi.commons.Trace;
import com.sissi.pipeline.TransferBuffer;
import com.sissi.protocol.iq.bytestreams.BytestreamsProxy;
import com.sissi.resource.ResourceCounter;
import com.sissi.server.exchange.Exchanger;
import com.sissi.server.exchange.ExchangerContext;
import com.sissi.server.exchange.Terminal;
import com.sissi.server.netty.ChannelHandlerBuilder;

/**
* @author kim 2013年12月22日
*/
public class Socks5ProxyServerHandlerBuilder implements ChannelHandlerBuilder {

  private final AttributeKey<Exchanger> exchanger = AttributeKey.valueOf("exchanger");

  private final String resource = Sock5ProxyServerHandler.class.getSimpleName();

  private final Log log = LogFactory.getLog(this.getClass());

  private final ExchangerContext exchangerContext;

  private final ResourceCounter resourceCounter;

  private final byte[] init;

  private final byte[] cmd;

  public Socks5ProxyServerHandlerBuilder(BytestreamsProxy proxy, ExchangerContext exchangerContext, ResourceCounter resourceCounter) {
    super();
    this.resourceCounter = resourceCounter;
    this.exchangerContext = exchangerContext;
    this.init = this.prepareStatic(this.buildInit());
    this.cmd = this.prepareStatic(this.buildCmd(proxy));
  }

  private byte[] prepareStatic(ByteBuf buf) {
    byte[] staticInit = new byte[buf.readableBytes()];
    buf.readBytes(staticInit);
    return staticInit;
  }

  private ByteBuf buildInit() {
    ByteBuf buf = Unpooled.buffer();
    new SocksInitResponse(SocksAuthScheme.NO_AUTH).encodeAsByteBuf(buf);
    return buf;
  }

  private ByteBuf buildCmd(BytestreamsProxy proxy) {
    ByteBuf buf = Unpooled.buffer();
    new SocksCmdResponseWrap(proxy, new SocksCmdResponse(SocksCmdStatus.SUCCESS, SocksAddressType.DOMAIN)).encodeAsByteBuf(buf);
    return buf;
  }

  public Sock5ProxyServerHandler build() throws IOException {
    return new Sock5ProxyServerHandler();
  }

  private class Sock5ProxyServerHandler extends ChannelInboundHandlerAdapter {

    public void channelRegistered(final ChannelHandlerContext ctx) throws Exception {
      Socks5ProxyServerHandlerBuilder.this.resourceCounter.increment(Socks5ProxyServerHandlerBuilder.this.resource);
    }

    public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {
      // 接收方完毕后强制关闭发起方
      ctx.attr(Socks5ProxyServerHandlerBuilder.this.exchanger).get().close(Terminal.SOURCE);
      Socks5ProxyServerHandlerBuilder.this.resourceCounter.decrement(Socks5ProxyServerHandlerBuilder.this.resource);
    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
      Socks5ProxyServerHandlerBuilder.this.log.debug(cause.toString());
      Trace.trace(Socks5ProxyServerHandlerBuilder.this.log, cause);
      ctx.close();
    }

    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
      // 接收方超时
      if (evt.getClass() == IdleStateEvent.class && IdleStateEvent.class.cast(evt).state() == IdleState.WRITER_IDLE) {
        ctx.close();
      }
    }

    public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
      try {
        this.prepare(ctx, msg, ctx.write(this.bytebuf(msg))).flush();
      } finally {
        ReferenceCountUtil.release(msg);
      }
    }

    private ByteBuf bytebuf(Object msg) {
      return msg.getClass() == SocksInitRequest.class ? Unpooled.wrappedBuffer(Socks5ProxyServerHandlerBuilder.this.init) : Unpooled.wrappedBuffer(Socks5ProxyServerHandlerBuilder.this.cmd);
    }

    private ChannelHandlerContext prepare(final ChannelHandlerContext ctx, Object msg, ChannelFuture future) throws IOException {
      if (msg.getClass() == SocksCmdRequest.class) {
        SocksCmdRequest cmd = SocksCmdRequest.class.cast(msg);
        return Socks5ProxyServerHandlerBuilder.this.exchangerContext.exists(cmd.host()) ? this.activate(Socks5ProxyServerHandlerBuilder.this.exchangerContext.activate(cmd.host()), future, ctx) : this.wait(cmd, ctx);
      }
      return ctx;
    }

    /**
     * 禁止关闭接收方,cascade = false
     *
     * @param cmd
     * @param ctx
     * @return
     * @throws IOException
     */
    private ChannelHandlerContext wait(SocksCmdRequest cmd, ChannelHandlerContext ctx) throws IOException {
      ctx.attr(Socks5ProxyServerHandlerBuilder.this.exchanger).set(Socks5ProxyServerHandlerBuilder.this.exchangerContext.wait(cmd.host(), false, new NetworkTransfer(ctx)));
      return ctx;
    }

    private ChannelHandlerContext activate(Exchanger exchanger, ChannelFuture future, ChannelHandlerContext ctx) throws IOException {
      future.addListener(new BridgeExchangeListener(ctx, exchanger));
      return ctx;
    }

    private class BridgeExchangeListener implements GenericFutureListener<Future<Void>> {

      private final ChannelHandlerContext ctx;

      private final Exchanger exchanger;

      public BridgeExchangeListener(ChannelHandlerContext ctx, Exchanger exchanger) {
        super();
        this.ctx = ctx;
        this.exchanger = exchanger.source(new ChannelHandlerContextCloseable(ctx));
      }

      @Override
      public void operationComplete(Future<Void> future) throws Exception {
        if (future.isSuccess()) {
          ctx.pipeline().remove(IdleStateHandler.class);
          ctx.pipeline().addFirst(new BridgeExchangerServerHandler());
          ctx.pipeline().context(BridgeExchangerServerHandler.class).attr(Socks5ProxyServerHandlerBuilder.this.exchanger).set(this.exchanger);
        }
      }
    }
  }

  @Sharable
  private class BridgeExchangerServerHandler extends ChannelInboundHandlerAdapter {

    public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {
      // 尝试关闭接收方
      ctx.attr(Socks5ProxyServerHandlerBuilder.this.exchanger).get().close(Terminal.TARGET);
      Socks5ProxyServerHandlerBuilder.this.resourceCounter.decrement(Socks5ProxyServerHandlerBuilder.this.resource);
    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
      Socks5ProxyServerHandlerBuilder.this.log.debug(cause.toString());
      Trace.trace(Socks5ProxyServerHandlerBuilder.this.log, cause);
      ctx.close();
    }

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
      try {
        ctx.attr(Socks5ProxyServerHandlerBuilder.this.exchanger).get().write(new ByteBufWrapTransferBuffer(ByteBuf.class.cast(msg)));
      } catch (Exception e) {
        ReferenceCountUtil.release(msg);
      }
    }
  }

  private class ChannelHandlerContextCloseable implements Closeable {

    private final ChannelHandlerContext ctx;

    public ChannelHandlerContextCloseable(ChannelHandlerContext ctx) {
      super();
      this.ctx = ctx;
    }

    @Override
    public void close() throws IOException {
      this.ctx.close();
    }
  }

  private class ByteBufWrapTransferBuffer implements TransferBuffer {

    private final ByteBuf buffer;

    public ByteBufWrapTransferBuffer(ByteBuf buffer) {
      super();
      this.buffer = buffer;
    }

    @Override
    public Object getBuffer() {
      return this.buffer;
    }

    @Override
    public TransferBuffer release() {
      if (this.buffer.refCnt() > 0) {
        ReferenceCountUtil.release(this.buffer);
      }
      return this;
    }
  }

  private class SocksCmdResponseWrap extends SocksResponse {

    private final byte START_DOMAIN = 4;

    private BytestreamsProxy proxy;

    private SocksCmdResponse cmd;

    protected SocksCmdResponseWrap(BytestreamsProxy proxy, SocksCmdResponse cmd) {
      super(cmd.responseType());
      this.cmd = cmd;
      this.proxy = proxy;
    }

    @Override
    public void encodeAsByteBuf(ByteBuf buf) {
      try {
        this.cmd.encodeAsByteBuf(buf);
        byte[] proxy = this.proxy.getDomain().getBytes("UTF-8");
        buf.writerIndex(START_DOMAIN).writeByte(proxy.length).writeBytes(proxy).writeByte(0).writeByte(0);
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
  }
}
TOP

Related Classes of com.sissi.server.netty.impl.Socks5ProxyServerHandlerBuilder$ChannelHandlerContextCloseable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.