23 | * Title: HessianEncoder.java 24 | *
25 | *26 | * Description: 描述 27 | *
28 | * 29 | * @author saber miao 30 | * @version 1.0 31 | * @created 2010-9-13 上午09:54:01 32 | */ 33 | public class HessianEncoder extends OneToOneEncoder { 34 | 35 | private static final Logger log = Logger.getLogger(SerializerFactory.class.getName()); 36 | 37 | private final int estimatedLength = 512; 38 | 39 | protected static final byte[] LENGTH_PLACEHOLDER = new byte[7]; 40 | 41 | protected void afterDo(ChannelBuffer cb){ 42 | cb.setInt(3, cb.writerIndex() - 7); 43 | } 44 | 45 | static { 46 | // Eliminate Hessian SerializerFactory class's warning log, in order to cooperate with pigeon.net framework 47 | log.setLevel(Level.SEVERE); 48 | } 49 | 50 | public Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { 51 | if (msg instanceof ChannelBuffer){ 52 | return msg; 53 | } 54 | ChannelBufferOutputStream bout = new ChannelBufferOutputStream(dynamicBuffer(estimatedLength, ctx.getChannel().getConfig().getBufferFactory())); 55 | bout.write(LENGTH_PLACEHOLDER); 56 | Hessian2Output h2out = new Hessian2Output(bout); 57 | try { 58 | h2out.writeObject(msg); 59 | h2out.flush(); 60 | } finally { 61 | h2out.close(); 62 | } 63 | ChannelBuffer encoded = bout.buffer(); 64 | afterDo(encoded); 65 | return encoded; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/protocals/README.md: -------------------------------------------------------------------------------- 1 | protocals to support 2 | ------- 3 | MongoDB: 4 | [http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/](http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/) 5 | 6 | Hession: 7 | 8 | 9 | -DsocksProxyHost=127.0.0.1 -DsocksProxyPort=40310 -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/protocals/pigeon-nullresponse.txt: -------------------------------------------------------------------------------- 1 | 0000 39 3A 02 00 00 00 69 4F 53 00 2A 63 6F 6D 2E 64 9: iOS *com.d 2 | 0001 69 61 6E 70 69 6E 67 2E 64 70 73 66 2E 70 72 6F ianping.dpsf.pro 3 | 0002 74 6F 63 6F 6C 2E 44 65 66 61 75 6C 74 52 65 73 tocol.DefaultRes 4 | 0003 70 6F 6E 73 65 95 03 73 65 71 0B 6D 65 73 73 61 ponse�seqmessa 5 | 0004 67 65 54 79 70 65 05 63 61 75 73 65 09 72 65 74 geTypecause ret 6 | 0005 75 72 6E 56 61 6C 07 63 6F 6E 74 65 78 74 6F 90 urnValcontexto� 7 | 0006 E4 92 4E 4E 4E 00 00 00 00 00 00 00 04 1D 1E 1F �NNN 8 | 0007 9 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/protocals/pigeon-shopservice.txt: -------------------------------------------------------------------------------- 1 | 0000 39 3A 03 00 00 00 91 05 73 72 01 00 29 63 6F 6D 9: �sr )com 2 | 0001 2E 64 69 61 6E 70 69 6E 67 2E 64 70 73 66 2E 70 .dianping.dpsf.p 3 | 0002 72 6F 74 6F 63 6F 6C 2E 44 65 66 61 75 6C 74 52 rotocol.DefaultR 4 | 0003 65 71 75 65 73 74 78 70 00 00 00 00 00 00 00 01 equestxp 5 | 0004 00 00 00 00 00 00 00 02 03 00 00 75 30 70 74 00 u0pt 6 | 0005 09 68 65 61 72 74 42 65 61 74 70 74 00 3A 68 74 heartBeatpt :ht 7 | 0006 74 70 3A 2F 2F 73 65 72 76 69 63 65 2E 64 69 61 tp://service.dia 8 | 0007 6E 70 69 6E 67 2E 63 6F 6D 2F 70 69 65 67 6F 6E nping.com/piegon 9 | 0008 53 65 72 76 69 63 65 2F 68 65 61 72 74 54 61 73 Service/heartTas 10 | 0009 6B 53 65 72 76 69 63 65 39 3A 02 00 00 00 E1 4F kService9: � 11 | 000A 53 00 29 63 6F 6D 2E 64 69 61 6E 70 69 6E 67 2E S )com.dianping. 12 | 000B 64 70 73 66 2E 70 72 6F 74 6F 63 6F 6C 2E 44 65 dpsf.protocol.De 13 | 000C 66 61 75 6C 74 52 65 71 75 65 73 74 99 09 73 65 faultRequest� se 14 | 000D 72 69 61 6C 69 7A 65 03 73 65 71 08 63 61 6C 6C rializeseqcall 15 | 000E 54 79 70 65 07 74 69 6D 65 6F 75 74 0B 73 65 72 Typetimeoutser 16 | 000F 76 69 63 65 4E 61 6D 65 0A 6D 65 74 68 6F 64 4E viceName 17 | methodN 18 | 0010 61 6D 65 0B 6D 65 73 73 61 67 65 54 79 70 65 0A amemessageType 19 | 20 | 0011 70 61 72 61 6D 65 74 65 72 73 07 63 6F 6E 74 65 parametersconte 21 | 0012 78 74 6F 90 92 E4 91 D4 1F 40 53 00 39 68 74 74 xto����@S 9htt 22 | 0013 70 3A 2F 2F 73 65 72 76 69 63 65 2E 64 69 61 6E p://service.dian 23 | 0014 70 69 6E 67 2E 63 6F 6D 2F 73 68 6F 70 53 65 72 ping.com/shopSer 24 | 0015 76 69 63 65 2F 73 68 6F 70 53 65 72 76 69 63 65 vice/shopService 25 | 0016 5F 32 2E 30 2E 30 08 6C 6F 61 64 53 68 6F 70 92 _2.0.0loadShop� 26 | 0017 56 74 00 07 5B 6F 62 6A 65 63 74 6E 01 91 7A 4E Vt [objectn�zN 27 | 0018 28 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/proxy/ForwardHandler.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.proxy; 2 | 3 | import com.dianping.mocksocks.transport.Connection; 4 | import org.jboss.netty.buffer.ChannelBuffer; 5 | import org.jboss.netty.channel.*; 6 | 7 | /** 8 | * Replay handler with status capture. 9 | * 10 | * @author yihua.huang@dianping.com 11 | */ 12 | public class ForwardHandler extends OutboundHandler implements ChannelDownstreamHandler { 13 | 14 | private final Connection connection; 15 | 16 | public ForwardHandler(Channel inboundChannel, String name, Connection connection) { 17 | super(inboundChannel, connection); 18 | this.connection = connection; 19 | } 20 | 21 | @Override 22 | public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception { 23 | final ChannelBuffer msg = (ChannelBuffer) e.getMessage(); 24 | connection.response(msg); 25 | super.messageReceived(ctx, e); 26 | } 27 | 28 | @Override 29 | public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { 30 | super.channelClosed(ctx, e); 31 | connection.close(); 32 | } 33 | 34 | @Override 35 | public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { 36 | super.exceptionCaught(ctx, e); 37 | connection.close(); 38 | } 39 | 40 | public Connection getConnection() { 41 | return connection; 42 | } 43 | 44 | @Override 45 | public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { 46 | if (e instanceof MessageEvent) { 47 | Object message = ((MessageEvent) e).getMessage(); 48 | if (message instanceof ChannelBuffer) { 49 | connection.request((ChannelBuffer) message); 50 | } 51 | } 52 | ctx.sendDownstream(e); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/proxy/MockSocksServerConnectHandler.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.proxy; 2 | 3 | import com.dianping.mocksocks.transport.Connection; 4 | import com.dianping.mocksocks.transport.protocals.CodecSelector; 5 | import org.jboss.netty.channel.*; 6 | import org.jboss.netty.handler.codec.socks.SocksCmdRequest; 7 | import org.jboss.netty.handler.codec.socks.SocksCmdResponse; 8 | import org.jboss.netty.handler.codec.socks.SocksMessage; 9 | 10 | import java.net.InetSocketAddress; 11 | 12 | /** 13 | * @author yihua.huang@dianping.com 14 | */ 15 | public class MockSocksServerConnectHandler extends SimpleChannelUpstreamHandler { 16 | 17 | private static final String name = "MOCK_SOCKS_SERVER_CONNECT_HANDLER"; 18 | 19 | public static String getName() { 20 | return name; 21 | } 22 | 23 | public MockSocksServerConnectHandler() { 24 | } 25 | 26 | @Override 27 | public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { 28 | final SocksCmdRequest socksCmdRequest = (SocksCmdRequest) e.getMessage(); 29 | final Channel inboundChannel = e.getChannel(); 30 | inboundChannel.setReadable(false); 31 | final InetSocketAddress remoteAddress = new InetSocketAddress(socksCmdRequest.getHost(), 32 | socksCmdRequest.getPort()); 33 | 34 | // decide protocol by port 35 | ChannelUpstreamHandler decoder = CodecSelector.decoder(remoteAddress, null); 36 | final Connection connection = new Connection(); 37 | // client数据转发到外部server 38 | inboundChannel.write(new SocksCmdResponse(SocksMessage.CmdStatus.SUCCESS, socksCmdRequest.getAddressType())); 39 | inboundChannel.setReadable(true); 40 | decoder = CodecSelector.decoder(remoteAddress, null); 41 | if (decoder != null) { 42 | inboundChannel.getPipeline().addLast("decoder" + decoder.getClass().getName(), decoder); 43 | } 44 | ctx.getPipeline().remove(getName()); 45 | // inboundChannel.getPipeline().addLast("output", new 46 | } 47 | 48 | @Override 49 | public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { 50 | super.exceptionCaught(ctx, e); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/proxy/OutboundHandler.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.proxy; 2 | 3 | import com.dianping.mocksocks.transport.Connection; 4 | import org.jboss.netty.buffer.ChannelBuffer; 5 | import org.jboss.netty.buffer.ChannelBuffers; 6 | import org.jboss.netty.channel.*; 7 | 8 | /** 9 | * @author yihua.huang@dianping.com 10 | */ 11 | public class OutboundHandler extends SimpleChannelUpstreamHandler { 12 | 13 | private final Channel inboundChannel; 14 | 15 | private String name; 16 | 17 | private Connection connection; 18 | 19 | OutboundHandler(Channel inboundChannel, Connection connection) { 20 | this.inboundChannel = inboundChannel; 21 | this.connection = connection; 22 | } 23 | 24 | @Override 25 | public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception { 26 | final ChannelBuffer msg = (ChannelBuffer) e.getMessage(); 27 | inboundChannel.write(msg); 28 | super.messageReceived(ctx, e); 29 | } 30 | 31 | @Override 32 | public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { 33 | closeOnFlush(inboundChannel); 34 | } 35 | 36 | @Override 37 | public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { 38 | closeOnFlush(e.getChannel()); 39 | inboundChannel.close(); 40 | } 41 | 42 | /** 43 | * Closes the specified channel after all queued write requests are flushed. 44 | */ 45 | static void closeOnFlush(Channel ch) { 46 | if (ch.isConnected()) { 47 | ch.write(ChannelBuffers.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); 48 | } 49 | } 50 | 51 | public String getName() { 52 | return name; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/proxy/ProxyConfig.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.proxy; 2 | 3 | /** 4 | * @author yihua.huang@dianping.com 5 | */ 6 | public class ProxyConfig { 7 | 8 | public enum Mode { 9 | Proxy, Mock; 10 | } 11 | 12 | private Mode mode; 13 | 14 | private boolean record; 15 | 16 | public static ProxyConfig custom(){ 17 | return new ProxyConfig(); 18 | } 19 | 20 | public ProxyConfig setMode(Mode mode) { 21 | this.mode = mode; 22 | return this; 23 | } 24 | 25 | public ProxyConfig setRecord(boolean record) { 26 | this.record = record; 27 | return this; 28 | } 29 | 30 | public Mode getMode() { 31 | return mode; 32 | } 33 | 34 | public boolean isRecord() { 35 | return record; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/proxy/ProxySocksServerConnectHandler.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.proxy; 2 | 3 | import com.dianping.mocksocks.transport.Connection; 4 | import com.dianping.mocksocks.transport.monitor.config.Configs; 5 | import com.dianping.mocksocks.transport.monitor.ConnectionMonitor; 6 | import com.dianping.mocksocks.transport.protocals.CodecSelector; 7 | import com.dianping.mocksocks.transport.rules.RulesContainer; 8 | import org.jboss.netty.bootstrap.ClientBootstrap; 9 | import org.jboss.netty.channel.*; 10 | import org.jboss.netty.channel.socket.ClientSocketChannelFactory; 11 | import org.jboss.netty.handler.codec.socks.SocksCmdRequest; 12 | import org.jboss.netty.handler.codec.socks.SocksCmdResponse; 13 | import org.jboss.netty.handler.codec.socks.SocksMessage; 14 | 15 | import java.net.InetSocketAddress; 16 | import java.nio.channels.ClosedChannelException; 17 | 18 | /** 19 | * @author yihua.huang@dianping.com 20 | */ 21 | public class ProxySocksServerConnectHandler extends SimpleChannelUpstreamHandler { 22 | 23 | private static final String name = "PROXY_SOCKS_SERVER_CONNECT_HANDLER"; 24 | 25 | public static String getName() { 26 | return name; 27 | } 28 | 29 | private final ClientSocketChannelFactory cf; 30 | 31 | private volatile Channel outboundChannel; 32 | 33 | public ProxySocksServerConnectHandler(ClientSocketChannelFactory cf) { 34 | this.cf = cf; 35 | } 36 | 37 | @Override 38 | public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { 39 | final SocksCmdRequest socksCmdRequest = (SocksCmdRequest) e.getMessage(); 40 | final Channel inboundChannel = e.getChannel(); 41 | inboundChannel.setReadable(false); 42 | 43 | // Start the connection attempt. 44 | final ClientBootstrap cb = new ClientBootstrap(cf); 45 | cb.setOption("keepAlive", true); 46 | cb.setOption("tcpNoDelay", true); 47 | final InetSocketAddress remoteAddress = RulesContainer.getInstance().getRedirectAddress( 48 | new InetSocketAddress(socksCmdRequest.getHost(), socksCmdRequest.getPort())); 49 | final Connection connection = new Connection(); 50 | if (socksCmdRequest.getPort() == 80) { 51 | connection.setProtocol("http"); 52 | } 53 | cb.setPipelineFactory(new ChannelPipelineFactory() { 54 | @Override 55 | public ChannelPipeline getPipeline() throws Exception { 56 | ChannelPipeline pipeline = Channels.pipeline(); 57 | // 外部server数据转发到client 58 | ForwardHandler handler = new ForwardHandler(inboundChannel, socksCmdRequest.getHost() + ":" 59 | + socksCmdRequest.getPort() + "<<<", connection); 60 | pipeline.addLast(ForwardHandler.class.getName(), handler); 61 | return pipeline; 62 | } 63 | }); 64 | 65 | ChannelFuture f = cb.connect(remoteAddress); 66 | outboundChannel = f.getChannel(); 67 | connection.setChannel(outboundChannel); 68 | if (Configs.getInstance().isRecord()) { 69 | ConnectionMonitor.getInstance().putStatus(outboundChannel, connection); 70 | } 71 | 72 | f.addListener(new ChannelFutureListener() { 73 | public void operationComplete(ChannelFuture future) throws Exception { 74 | if (future.isSuccess()) { 75 | connection.start(); 76 | // decide protocol by port 77 | ChannelUpstreamHandler decoder = CodecSelector.decoder(remoteAddress, null); 78 | if (decoder != null) { 79 | outboundChannel.getPipeline().addLast("decoder" + decoder.getClass().getName(), decoder); 80 | } 81 | // client数据转发到外部server 82 | inboundChannel.getPipeline().addLast("inboundChannel", 83 | new OutboundHandler(outboundChannel, connection)); 84 | inboundChannel.write(new SocksCmdResponse(SocksMessage.CmdStatus.SUCCESS, socksCmdRequest 85 | .getAddressType())); 86 | inboundChannel.setReadable(true); 87 | decoder = CodecSelector.decoder(remoteAddress, null); 88 | if (decoder != null) { 89 | inboundChannel.getPipeline().addLast("decoder" + decoder.getClass().getName(), decoder); 90 | } 91 | ctx.getPipeline().remove(getName()); 92 | // inboundChannel.getPipeline().addLast("output", new 93 | // OutPutHandler()); 94 | } else { 95 | connection.setStatus(Connection.FAIL); 96 | inboundChannel.write(new SocksCmdResponse(SocksMessage.CmdStatus.FAILURE, socksCmdRequest 97 | .getAddressType())); 98 | inboundChannel.close(); 99 | ctx.getPipeline().remove(getName()); 100 | } 101 | } 102 | }); 103 | } 104 | 105 | @Override 106 | public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { 107 | if (e.getCause() instanceof ClosedChannelException) { 108 | // do nothing 109 | } else { 110 | super.exceptionCaught(ctx, e); 111 | } 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/proxy/SocksMessageEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package com.dianping.mocksocks.transport.proxy; 17 | 18 | import org.jboss.netty.buffer.ChannelBuffer; 19 | import org.jboss.netty.buffer.ChannelBuffers; 20 | import org.jboss.netty.channel.Channel; 21 | import org.jboss.netty.channel.ChannelHandler; 22 | import org.jboss.netty.channel.ChannelHandlerContext; 23 | import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; 24 | import org.jboss.netty.handler.codec.socks.SocksMessage; 25 | 26 | /** 27 | * Encodes an {@link org.jboss.netty.handler.codec.socks.SocksMessage} into a 28 | * {@link org.jboss.netty.buffer.ChannelBuffer}. 29 | * {@link org.jboss.netty.handler.codec.oneone.OneToOneEncoder} implementation. 30 | * Use this with {@link org.jboss.netty.handler.codec.socks.SocksInitRequest}, 31 | * {@link org.jboss.netty.handler.codec.socks.SocksInitResponse}, 32 | * {@link org.jboss.netty.handler.codec.socks.SocksAuthRequest}, 33 | * {@link org.jboss.netty.handler.codec.socks.SocksAuthResponse}, 34 | * {@link org.jboss.netty.handler.codec.socks.SocksCmdRequest} and 35 | * {@link org.jboss.netty.handler.codec.socks.SocksCmdResponse} 36 | */ 37 | @ChannelHandler.Sharable 38 | public class SocksMessageEncoder extends OneToOneEncoder { 39 | private static final String name = "SOCKS_MESSAGE_ENCODER"; 40 | private static final int DEFAULT_ENCODER_BUFFER_SIZE = 1024; 41 | 42 | public static String getName() { 43 | return name; 44 | } 45 | 46 | @Override 47 | protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { 48 | ChannelBuffer buffer = null; 49 | if (msg instanceof SocksMessage) { 50 | buffer = ChannelBuffers.buffer(DEFAULT_ENCODER_BUFFER_SIZE); 51 | ((SocksMessage) msg).encodeAsByteBuf(buffer); 52 | return buffer; 53 | } 54 | return msg; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/proxy/SocksProxy.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.proxy; 2 | 3 | import com.dianping.mocksocks.transport.Proxy; 4 | import org.jboss.netty.bootstrap.ServerBootstrap; 5 | import org.jboss.netty.channel.socket.ClientSocketChannelFactory; 6 | import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; 7 | import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; 8 | 9 | import java.net.InetSocketAddress; 10 | import java.util.concurrent.Executor; 11 | import java.util.concurrent.Executors; 12 | import java.util.concurrent.atomic.AtomicBoolean; 13 | 14 | /** 15 | * @author yihua.huang@dianping.com 16 | */ 17 | public class SocksProxy implements Proxy { 18 | 19 | private ServerBootstrap sb; 20 | 21 | private AtomicBoolean running = new AtomicBoolean(false); 22 | 23 | private ProxyConfig proxyConfig; 24 | 25 | public void run() { 26 | 27 | proxyConfig = new ProxyConfig(); 28 | proxyConfig.setMode(ProxyConfig.Mode.Proxy); 29 | 30 | // Configure the bootstrap. 31 | Executor executor = Executors.newCachedThreadPool(); 32 | Executor executorWorker = Executors.newCachedThreadPool(); 33 | sb = new ServerBootstrap(new NioServerSocketChannelFactory(executor, executorWorker)); 34 | 35 | // Set up the event pipeline factory. 36 | ClientSocketChannelFactory cf = new NioClientSocketChannelFactory(executor, executorWorker); 37 | 38 | sb.setPipelineFactory(new SocksProxyPipelineFactory(cf,proxyConfig)); 39 | 40 | // Start up the server. 41 | sb.bind(new InetSocketAddress(13721)); 42 | } 43 | 44 | public static void main(String[] args) { 45 | new SocksProxy().run(); 46 | } 47 | 48 | @Override 49 | public void start() { 50 | if (running.compareAndSet(false, true)) { 51 | try { 52 | run(); 53 | } catch (RuntimeException e) { 54 | running.compareAndSet(true, false); 55 | throw e; 56 | } 57 | } 58 | } 59 | 60 | @Override 61 | public void stop() { 62 | if (running.compareAndSet(true, false)) { 63 | sb.shutdown(); 64 | } 65 | } 66 | 67 | @Override 68 | public void loadCache(String cacheFile) { 69 | 70 | } 71 | 72 | @Override 73 | public boolean isRunning() { 74 | return running.get(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/proxy/SocksProxyPipelineFactory.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.proxy; 2 | 3 | import org.jboss.netty.channel.ChannelPipeline; 4 | import org.jboss.netty.channel.ChannelPipelineFactory; 5 | import org.jboss.netty.channel.Channels; 6 | import org.jboss.netty.channel.socket.ClientSocketChannelFactory; 7 | import org.jboss.netty.handler.codec.socks.SocksInitRequestDecoder; 8 | 9 | /** 10 | * @author yihua.huang@dianping.com 11 | */ 12 | public class SocksProxyPipelineFactory implements ChannelPipelineFactory { 13 | 14 | private final ClientSocketChannelFactory cf; 15 | 16 | private ProxyConfig proxyConfig; 17 | 18 | public SocksProxyPipelineFactory(ClientSocketChannelFactory cf, ProxyConfig proxyConfig) { 19 | this.cf = cf; 20 | this.proxyConfig = proxyConfig; 21 | } 22 | 23 | @Override 24 | public ChannelPipeline getPipeline() throws Exception { 25 | ChannelPipeline pipeline = Channels.pipeline(); 26 | pipeline.addLast(SocksInitRequestDecoder.getName(), new SocksInitRequestDecoder()); 27 | pipeline.addLast(SocksMessageEncoder.getName(), new SocksMessageEncoder()); 28 | pipeline.addLast(SocksServerHandler.getName(), new SocksServerHandler(proxyConfig, cf)); 29 | return pipeline; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/proxy/SocksServerHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package com.dianping.mocksocks.transport.proxy; 17 | 18 | import org.jboss.netty.channel.ChannelHandlerContext; 19 | import org.jboss.netty.channel.MessageEvent; 20 | import org.jboss.netty.channel.SimpleChannelUpstreamHandler; 21 | import org.jboss.netty.channel.socket.ClientSocketChannelFactory; 22 | import org.jboss.netty.handler.codec.socks.*; 23 | 24 | public final class SocksServerHandler extends SimpleChannelUpstreamHandler { 25 | private static final String name = "SOCKS_SERVER_HANDLER"; 26 | 27 | public static String getName() { 28 | return name; 29 | } 30 | 31 | private ProxyConfig proxyConfig; 32 | 33 | private final ClientSocketChannelFactory cf; 34 | 35 | public SocksServerHandler( ProxyConfig proxyConfig,ClientSocketChannelFactory cf) { 36 | this.proxyConfig = proxyConfig; 37 | this.cf = cf; 38 | } 39 | 40 | @Override 41 | public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { 42 | SocksRequest socksRequest = (SocksRequest) e.getMessage(); 43 | switch (socksRequest.getSocksRequestType()) { 44 | case INIT: 45 | // 添加cmd解码器 46 | ctx.getPipeline().addFirst(SocksCmdRequestDecoder.getName(), new SocksCmdRequestDecoder()); 47 | // 简单起见,无需认证 48 | ctx.getChannel().write(new SocksInitResponse(SocksMessage.AuthScheme.NO_AUTH)); 49 | break; 50 | case AUTH: 51 | ctx.getPipeline().addFirst(SocksCmdRequestDecoder.getName(), new SocksCmdRequestDecoder()); 52 | // 直接成功 53 | ctx.getChannel().write(new SocksAuthResponse(SocksMessage.AuthStatus.SUCCESS)); 54 | break; 55 | case CMD: 56 | SocksCmdRequest req = (SocksCmdRequest) socksRequest; 57 | if (req.getCmdType() == SocksMessage.CmdType.CONNECT) { 58 | // 添加处理连接的handler 59 | if (proxyConfig.getMode() == ProxyConfig.Mode.Proxy) { 60 | ctx.getPipeline().addLast(ProxySocksServerConnectHandler.getName(), 61 | new ProxySocksServerConnectHandler(cf)); 62 | } else { 63 | ctx.getPipeline().addLast(ProxySocksServerConnectHandler.getName(), 64 | new MockSocksServerConnectHandler()); 65 | } 66 | ctx.getPipeline().remove(this); 67 | } else { 68 | ctx.getChannel().close(); 69 | } 70 | break; 71 | case UNKNOWN: 72 | break; 73 | } 74 | super.messageReceived(ctx, e); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/rules/RedirectRule.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.rules; 2 | 3 | import com.dianping.mocksocks.transport.rules.filter.HostFilter; 4 | import com.dianping.mocksocks.transport.utils.AddressUtils; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import java.net.InetSocketAddress; 8 | import java.net.UnknownHostException; 9 | 10 | /** 11 | * @author yihua.huang@dianping.com 12 | */ 13 | public class RedirectRule { 14 | 15 | private HostFilter hostFilter; 16 | 17 | private InetSocketAddress inetSocketAddress; 18 | 19 | public RedirectRule(HostFilter hostFilter, InetSocketAddress inetSocketAddress) { 20 | this.hostFilter = hostFilter; 21 | this.inetSocketAddress = inetSocketAddress; 22 | } 23 | 24 | public HostFilter getHostFilter() { 25 | return hostFilter; 26 | } 27 | 28 | public void setHostFilter(HostFilter hostFilter) { 29 | this.hostFilter = hostFilter; 30 | } 31 | 32 | public InetSocketAddress getInetSocketAddress() { 33 | return inetSocketAddress; 34 | } 35 | 36 | public void setInetSocketAddress(InetSocketAddress inetSocketAddress) { 37 | this.inetSocketAddress = inetSocketAddress; 38 | } 39 | 40 | public static RedirectRule parse(String expr) { 41 | if (StringUtils.isBlank(expr)) { 42 | return null; 43 | } 44 | String[] tokens = expr.split("\\s+"); 45 | HostFilter hostFilter = new HostFilter(tokens[0]); 46 | try { 47 | InetSocketAddress inetSocketAddress = AddressUtils.parse(tokens[1]); 48 | return new RedirectRule(hostFilter,inetSocketAddress); 49 | } catch (UnknownHostException e) { 50 | throw new IllegalArgumentException("Error in line:\"" + expr + "\"", e); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/rules/RulesContainer.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.rules; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import java.net.InetSocketAddress; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * @author yihua.huang@dianping.com 11 | */ 12 | public class RulesContainer { 13 | 14 | private final static RulesContainer INSTANCE = new RulesContainer(); 15 | 16 | public static RulesContainer getInstance() { 17 | return INSTANCE; 18 | } 19 | 20 | private List