├── README.md ├── ROADMAP.md ├── bin ├── client.jar ├── lib │ ├── asm-3.0.jar │ ├── asm-commons-3.0.jar │ ├── asm-tree-3.0.jar │ ├── commons-dbutils-1.5.jar │ ├── commons-lang3-3.1.jar │ ├── forms-1.1-preview.jar │ ├── forms_rt-7.0.3.jar │ ├── h2-1.3.174.jar │ ├── hessian-4.0.8.jar │ ├── jdom-1.0.jar │ ├── jgoodies-binding-2.7.0.jar │ ├── jgoodies-common-1.4.0.jar │ ├── jgoodies-forms-1.6.0.jar │ ├── mocksocks-proxy-0.0.2-SNAPSHOT.jar │ └── netty-3.7.0.Final.jar └── mocksocks.jar ├── docs ├── README-en.md ├── connection model stateless protocol.png ├── proxy.graffle ├── proxy.png ├── schedule.jpeg └── screenshot.png ├── install.sh ├── make.sh ├── mocksocks-client ├── pom.xml └── src │ └── main │ └── java │ ├── com.dianping.mocksocks.client │ ├── agent │ │ └── SocksAgent.java │ └── socks │ │ └── SocksProxySelectorProvider.java │ └── sun │ └── nio │ └── ch │ ├── OptionAdaptor2.java │ ├── SocketAdaptor2.java │ ├── SocketChannelImpl2.java │ └── SocksProxySocketChannel.java ├── mocksocks-gui ├── asserts │ └── icons.graffle ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── dianping │ │ └── mocksocks │ │ └── gui │ │ ├── data │ │ ├── ConnectionStatusListModel.java │ │ └── MessageListModel.java │ │ └── gui │ │ ├── Menu.java │ │ ├── MessageDetailDialog.form │ │ ├── MessageDetailDialog.java │ │ ├── MocksocksDashboard.form │ │ ├── MocksocksDashboard.java │ │ ├── RedirectRulesDialog.form │ │ └── RedirectRulesDialog.java │ └── resources │ └── icon │ ├── record-start.png │ ├── record-stop.png │ └── status-clear.png ├── mocksocks-junit ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── dianping │ └── mocksocks │ └── junit │ └── MockSocksClassRunner.java ├── mocksocks-sample ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── dianping │ └── mocksocks │ └── sample │ └── telnet │ ├── TelnetClient.java │ ├── TelnetClientHandler.java │ └── TelnetClientPipelineFactory.java ├── mocksocks-transport ├── README.md ├── pom.xml ├── sql │ └── rules.sql └── src │ ├── main │ └── java │ │ └── com │ │ └── dianping │ │ └── mocksocks │ │ └── transport │ │ ├── Connection.java │ │ ├── Message.java │ │ ├── Proxy.java │ │ ├── Transmit.java │ │ ├── dao │ │ └── BaseDao.java │ │ ├── handler │ │ └── OutPutHandler.java │ │ ├── monitor │ │ ├── ConnectionMonitor.java │ │ ├── StatusFormatter.java │ │ └── config │ │ │ ├── Configs.java │ │ │ └── RulesDao.java │ │ ├── protocals │ │ ├── CodecSelector.java │ │ ├── HessianDecoder.java │ │ ├── HessianEncoder.java │ │ ├── README.md │ │ ├── pigeon-nullresponse.txt │ │ ├── pigeon-response.txt │ │ └── pigeon-shopservice.txt │ │ ├── proxy │ │ ├── ForwardHandler.java │ │ ├── MockSocksServerConnectHandler.java │ │ ├── OutboundHandler.java │ │ ├── ProxyConfig.java │ │ ├── ProxySocksServerConnectHandler.java │ │ ├── SocksMessageEncoder.java │ │ ├── SocksProxy.java │ │ ├── SocksProxyPipelineFactory.java │ │ └── SocksServerHandler.java │ │ ├── rules │ │ ├── RedirectRule.java │ │ ├── RulesContainer.java │ │ └── filter │ │ │ ├── ConnectionStatusHostFilter.java │ │ │ ├── Filter.java │ │ │ └── HostFilter.java │ │ └── utils │ │ └── AddressUtils.java │ └── test │ └── java │ └── com │ └── dianping │ └── mocksocks │ └── transport │ └── dao │ ├── BaseDapTest.java │ └── RulesDaoTest.java ├── mocksocks-web ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── dianping │ └── mocksocks │ └── web │ └── Bootstrap.java └── pom.xml /README.md: -------------------------------------------------------------------------------- 1 | MockSocks 2 | ======== 3 | > MockSocks多功能抓包和回放工具。它基于socks代理,可以拦截任何应用层协议,并做解析。此外还包括重定向、录制、回放等功能。 4 | 5 | ![proxy][1] 6 | 7 | ## 目标 8 | 9 | * ### (Java)后端程序的抓包工具 10 | 11 | MockSocks最初的定位是Java后端开发时,用于调试网络连接情况,以及远程请求内容的工具。因此需要达到在不修改任何业务代码的情况下,对Java程序进行抓包,并可对请求进行重定向、回放以及直接构造响应体。 12 | 13 | * ### 多种协议扩展 14 | 15 | MockSocks基于socks协议,可以拦截所有基于TCP的应用协议,包括HTTP、FTP、SMTP等公用协议,也支持mysql、mongo、memcached等私有协议,以及一些自定义的RPC协议和序列化方式。希望在程序内部以可扩展的方式,因此多种编码/解码器,从而达到对协议的支持。 16 | 17 | ## 安装 18 | 19 | curl http://code4craft.qiniudn.com/install.sh | [sudo] sh 20 | 21 | 默认安装到`/usr/local/mocksocks`目录 22 | 23 | ## 使用: 24 | 25 | ### 启动代理: 26 | 27 | java -jar /usr/local/mocksocks/mocksocks.jar 28 | 29 | ### Java程序客户端: 30 | 31 | 在VM参数中添加 32 | 33 | -javaagent:/usr/local/mocksocks/client.jar -DmockFile=/usr/local/mocksocks/client.jar 34 | 35 | 并启动。 36 | 37 | ### 查看 38 | 39 | 在界面上即可看到所有活跃连接,双击连接可查看内容! 40 | 41 | ![gui][3] 42 | 43 | ### 新UI: 44 | 45 | ![gui][4] 46 | 47 | ### 进展 48 | 49 | ![schedule][5] 50 | 51 | [1]: http://static.oschina.net/uploads/space/2013/1025/202527_iLkr_190591.png 52 | [2]: http://static.oschina.net/uploads/space/2013/1026/224012_KNGE_190591.png 53 | [3]: http://static.oschina.net/uploads/space/2013/1107/182714_ftTa_190591.png 54 | [4]: http://static.oschina.net/uploads/space/2013/1117/212244_eFUQ_190591.png 55 | [5]: http://static.oschina.net/uploads/space/2013/1128/165612_IeBV_190591.jpeg -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | MockSocks开发计划 2 | ======= 3 | 4 | MockSocks分为几个部分: 5 | 6 | * ### Java客户端(完成) 7 | 8 | 通过替换NIO SocketChannel实现,达到为NIO设置代理的效果。此部分使用javaagent达到不修改业务代码的目的,目前已开发完成,代码在`mocksocks-client`模块内。只需在程序启动时添加JVM参数即可: 9 | 10 | -javaagent:/path/to/mocksocks-client.jar -DmockFile=/path/to/mocksocks-client.jar 11 | 12 | * ### Socks代理服务器(完成) 13 | 14 | 提供Socks代理服务,保证一定性能的情况下,提供良好的扩展接口。此部分基于Netty开发,目前已开发完成,代码在`mocksocks-proxy`模块内。 15 | 16 | * ### 用户界面及功能(70%) 17 | 18 | 提供界面,让用户可以更方便的监控及修改。这部分使用swing实现,目前完成了连接显示、过滤、重定向模块。引入了h2做数据存储。完成度:40%? 19 | 20 | * ####流量录制 21 | 按照目标地址=>连接=>协议内容来区分。 22 | 23 | 某些协议是无状态的,例如Http/RPC/大部分nosql,这种是不是一个连接无所谓。 24 | 25 | 有些协议是有状态的,例如ftp/mysql,这种必须要对同一连接,并且有时间顺序。 26 | 27 | 一些已有的解决方案: 28 | 29 | wiredshark是显示TCP包,并可以follow sequence。Charles/fiddler是基于HTTP,每个HTTP协议体显示一个。倾向于这一种。可以先从无状态协议入手做。 30 | 31 | 无状态协议: 32 | 33 | 支持单连接串行Reuquest/Response,不支持pipeline。 34 | 35 | ![proxy][2] 36 | 37 | * ### 协议编码/解码(未开始) 38 | 39 | 提供可扩展的协议编解码接口,并实现常用协议的编码/解码器。主要针对目前公司使用的hessian序列化,并提供一个可映射到Java数据结构的文本结构,以供在调试时进行编辑。目前还未开始开发。 40 | 41 | * ### 与测试框架集成(未开始) 42 | 43 | MockSocks的初始动机是为测试时提供一个稳定的环境。可以在测试时,对请求内容进行抓包并持久化到本地,以后在回归测试时只需使用本地文件,大大增加测试的稳定性和减少对环境的依赖。这部分涉及到JUnit以及maven相关功能。目前还未开始开发。 44 | 45 | [1]: http://static.oschina.net/uploads/space/2013/1025/202527_iLkr_190591.png 46 | [2]: http://static.oschina.net/uploads/space/2013/1026/224012_KNGE_190591.png 47 | [3]: http://static.oschina.net/uploads/space/2013/1107/182714_ftTa_190591.png -------------------------------------------------------------------------------- /bin/client.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/client.jar -------------------------------------------------------------------------------- /bin/lib/asm-3.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/asm-3.0.jar -------------------------------------------------------------------------------- /bin/lib/asm-commons-3.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/asm-commons-3.0.jar -------------------------------------------------------------------------------- /bin/lib/asm-tree-3.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/asm-tree-3.0.jar -------------------------------------------------------------------------------- /bin/lib/commons-dbutils-1.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/commons-dbutils-1.5.jar -------------------------------------------------------------------------------- /bin/lib/commons-lang3-3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/commons-lang3-3.1.jar -------------------------------------------------------------------------------- /bin/lib/forms-1.1-preview.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/forms-1.1-preview.jar -------------------------------------------------------------------------------- /bin/lib/forms_rt-7.0.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/forms_rt-7.0.3.jar -------------------------------------------------------------------------------- /bin/lib/h2-1.3.174.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/h2-1.3.174.jar -------------------------------------------------------------------------------- /bin/lib/hessian-4.0.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/hessian-4.0.8.jar -------------------------------------------------------------------------------- /bin/lib/jdom-1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/jdom-1.0.jar -------------------------------------------------------------------------------- /bin/lib/jgoodies-binding-2.7.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/jgoodies-binding-2.7.0.jar -------------------------------------------------------------------------------- /bin/lib/jgoodies-common-1.4.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/jgoodies-common-1.4.0.jar -------------------------------------------------------------------------------- /bin/lib/jgoodies-forms-1.6.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/jgoodies-forms-1.6.0.jar -------------------------------------------------------------------------------- /bin/lib/mocksocks-proxy-0.0.2-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/mocksocks-proxy-0.0.2-SNAPSHOT.jar -------------------------------------------------------------------------------- /bin/lib/netty-3.7.0.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/lib/netty-3.7.0.Final.jar -------------------------------------------------------------------------------- /bin/mocksocks.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/bin/mocksocks.jar -------------------------------------------------------------------------------- /docs/README-en.md: -------------------------------------------------------------------------------- 1 | mocksocks 2 | -------- 3 | > A socks proxy in Java. It can be used to record network traffics and replay them for tests. 4 | 5 | ### Goals 6 | 7 | Record network traffics and replay them for tests. Then you can run tests isolately without considering the unstable external dependencies. 8 | 9 | ### Ways 10 | 11 | Set global socks proxy for Java. 12 | 13 | ### Planning 14 | 15 | ## Client: 16 | 17 | -DmockFile=/Users/yihua/dp_workspace/mocksocks/mocksocks-client/target/mocksocks-client-0.0.2-SNAPSHOT.jar -javaagent:/Users/yihua/dp_workspace/mocksocks/mocksocks-client/target/mocksocks-client-0.0.2-SNAPSHOT.jar 18 | 19 | init request: 20 | 21 | 22 | | version |authSchemeSize| authSchemes| 23 | |:------- | -----------:|:----------:| 24 | | 0x05 | 0x01 | 0x00 | 25 | 26 | ## Java Text 27 | 28 | [http://www.etsi.org/technologies-clusters/technologies/protocol-specification](http://www.etsi.org/technologies-clusters/technologies/protocol-specification) 29 | 30 | int 31 | 32 | string 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/connection model stateless protocol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/docs/connection model stateless protocol.png -------------------------------------------------------------------------------- /docs/proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/docs/proxy.png -------------------------------------------------------------------------------- /docs/schedule.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/docs/schedule.jpeg -------------------------------------------------------------------------------- /docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/docs/screenshot.png -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | FILE="mocksocks.tar.gz" 3 | URL="http://code4craft.qiniudn.com/${FILE}" 4 | LPATH="/usr/local/mocksocks" 5 | mkdir -p ${LPATH}; 6 | curl ${URL} > ${LPATH}/${FILE} 7 | cd ${LPATH} 8 | tar -xzf ${FILE} 9 | echo "Done!" 10 | echo "Add vm parameters '-javaagent:${LPATH}/client.jar -DmockFile=${LPATH}/client.jar' to your program" 11 | echo "try java -jar ${LPATH}/mocksocks.jar to run the GUI!" 12 | 13 | -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mvn clean package 3 | cp mocksocks-client/target/mocksocks-client*.jar bin/client.jar 4 | cp mocksocks-gui/target/mocksocks-gui*.jar bin/mocksocks.jar 5 | rsync -avz --delete mocksocks-gui/target/lib/ bin/lib/ 6 | -------------------------------------------------------------------------------- /mocksocks-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | mocksocks 7 | com.dianping 8 | 0.0.2-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | com.dianping 13 | mocksocks-client 14 | 0.0.2-SNAPSHOT 15 | 16 | 17 | 18 | 19 | org.apache.maven.plugins 20 | maven-jar-plugin 21 | 22 | 23 | 24 | com.dianping.mocksocks.client.agent.SocksAgent 25 | com.dianping.mocksocks.client.agent.SocksAgent 26 | true 27 | true 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-compiler-plugin 35 | 3.1 36 | 37 | 1.6 38 | 1.6 39 | utf-8 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /mocksocks-client/src/main/java/com.dianping.mocksocks.client/agent/SocksAgent.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.client.agent; 2 | 3 | import java.io.IOException; 4 | import java.lang.instrument.Instrumentation; 5 | import java.util.jar.JarFile; 6 | 7 | /** 8 | * @author yihua.huang@dianping.com 9 | */ 10 | public class SocksAgent { 11 | 12 | public static void premain(String agentArgs, Instrumentation inst) throws IOException { 13 | if (System.getProperty("socksProxyHost") == null) { 14 | System.setProperty("socksProxyHost", "127.0.0.1"); 15 | } 16 | if (System.getProperty("socksProxyPort") == null) { 17 | System.setProperty("socksProxyPort", "13721"); 18 | } 19 | String mockFile = System.getProperty("mockFile"); 20 | System.out.println("get mock file "+mockFile); 21 | if (mockFile != null) { 22 | inst.appendToBootstrapClassLoaderSearch(new JarFile(mockFile)); 23 | } 24 | System.setProperty("java.nio.channels.spi.SelectorProvider", 25 | "com.dianping.mocksocks.client.socks.SocksProxySelectorProvider"); 26 | 27 | } 28 | 29 | public static void agentmain(String args, Instrumentation inst) throws Exception { 30 | premain(args, inst); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /mocksocks-client/src/main/java/com.dianping.mocksocks.client/socks/SocksProxySelectorProvider.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.client.socks; 2 | 3 | import sun.nio.ch.SocksProxySocketChannel; 4 | 5 | import java.io.IOException; 6 | import java.nio.channels.DatagramChannel; 7 | import java.nio.channels.Pipe; 8 | import java.nio.channels.ServerSocketChannel; 9 | import java.nio.channels.SocketChannel; 10 | import java.nio.channels.spi.AbstractSelector; 11 | import java.nio.channels.spi.SelectorProvider; 12 | 13 | /** 14 | * @author yihua.huang@dianping.com 15 | */ 16 | public class SocksProxySelectorProvider extends SelectorProvider { 17 | 18 | private static volatile SelectorProvider innerProvider; 19 | 20 | public SocksProxySelectorProvider() { 21 | if (innerProvider == null) { 22 | synchronized (SocksProxySelectorProvider.class) { 23 | if (innerProvider == null) { 24 | innerProvider = sun.nio.ch.DefaultSelectorProvider.create(); 25 | } 26 | } 27 | } 28 | } 29 | 30 | @Override 31 | public DatagramChannel openDatagramChannel() throws IOException { 32 | return innerProvider.openDatagramChannel(); 33 | } 34 | 35 | @Override 36 | public Pipe openPipe() throws IOException { 37 | return innerProvider.openPipe(); 38 | } 39 | 40 | @Override 41 | public AbstractSelector openSelector() throws IOException { 42 | return innerProvider.openSelector(); 43 | } 44 | 45 | @Override 46 | public ServerSocketChannel openServerSocketChannel() throws IOException { 47 | return innerProvider.openServerSocketChannel(); 48 | } 49 | 50 | @Override 51 | public SocketChannel openSocketChannel() throws IOException { 52 | return new SocksProxySocketChannel(innerProvider); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /mocksocks-client/src/main/java/sun/nio/ch/OptionAdaptor2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Oracle designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Oracle in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 | * or visit www.oracle.com if you need additional information or have any 23 | * questions. 24 | */ 25 | 26 | package sun.nio.ch; 27 | 28 | import java.net.SocketException; 29 | 30 | 31 | // Adaptor class for java.net-style options 32 | // 33 | // The option get/set methods in the socket, server-socket, and datagram-socket 34 | // adaptors delegate to an instance of this class. 35 | // 36 | 37 | class OptionAdaptor2 { // package-private 38 | 39 | private final SocketOpts.IP opts; 40 | 41 | OptionAdaptor2(SocketChannelImpl2 sc) { 42 | opts = (SocketOpts.IP)sc.options(); 43 | } 44 | 45 | OptionAdaptor2(ServerSocketChannelImpl ssc) { 46 | opts = (SocketOpts.IP)ssc.options(); 47 | } 48 | 49 | OptionAdaptor2(DatagramChannelImpl dc) { 50 | opts = (SocketOpts.IP)dc.options(); 51 | } 52 | 53 | private SocketOpts.IP opts() { 54 | return opts; 55 | } 56 | 57 | private SocketOpts.IP.TCP tcpOpts() { 58 | return (SocketOpts.IP.TCP)opts; 59 | } 60 | 61 | public void setTcpNoDelay(boolean on) throws SocketException { 62 | try { 63 | tcpOpts().noDelay(on); 64 | } catch (Exception x) { 65 | Net.translateToSocketException(x); 66 | } 67 | } 68 | 69 | public boolean getTcpNoDelay() throws SocketException { 70 | try { 71 | return tcpOpts().noDelay(); 72 | } catch (Exception x) { 73 | Net.translateToSocketException(x); 74 | return false; // Never happens 75 | } 76 | } 77 | 78 | public void setSoLinger(boolean on, int linger) throws SocketException { 79 | try { 80 | if (linger > 65535) 81 | linger = 65535; 82 | opts().linger(on ? linger : -1); 83 | } catch (Exception x) { 84 | Net.translateToSocketException(x); 85 | } 86 | } 87 | 88 | public int getSoLinger() throws SocketException { 89 | try { 90 | return opts().linger(); 91 | } catch (Exception x) { 92 | Net.translateToSocketException(x); 93 | return 0; // Never happens 94 | } 95 | } 96 | 97 | public void setOOBInline(boolean on) throws SocketException { 98 | try { 99 | opts().outOfBandInline(on); 100 | } catch (Exception x) { 101 | Net.translateToSocketException(x); 102 | } 103 | } 104 | 105 | public boolean getOOBInline() throws SocketException { 106 | try { 107 | return opts().outOfBandInline(); 108 | } catch (Exception x) { 109 | Net.translateToSocketException(x); 110 | return false; // Never happens 111 | } 112 | } 113 | 114 | public void setSendBufferSize(int size) 115 | throws SocketException 116 | { 117 | try { 118 | opts().sendBufferSize(size); 119 | } catch (Exception x) { 120 | Net.translateToSocketException(x); 121 | } 122 | } 123 | 124 | public int getSendBufferSize() throws SocketException { 125 | try { 126 | return opts().sendBufferSize(); 127 | } catch (Exception x) { 128 | Net.translateToSocketException(x); 129 | return 0; // Never happens 130 | } 131 | } 132 | 133 | public void setReceiveBufferSize(int size) 134 | throws SocketException 135 | { 136 | try { 137 | opts().receiveBufferSize(size); 138 | } catch (Exception x) { 139 | Net.translateToSocketException(x); 140 | } 141 | } 142 | 143 | public int getReceiveBufferSize() throws SocketException { 144 | try { 145 | return opts().receiveBufferSize(); 146 | } catch (Exception x) { 147 | Net.translateToSocketException(x); 148 | return 0; // Never happens 149 | } 150 | } 151 | 152 | public void setKeepAlive(boolean on) throws SocketException { 153 | try { 154 | opts().keepAlive(on); 155 | } catch (Exception x) { 156 | Net.translateToSocketException(x); 157 | } 158 | } 159 | 160 | public boolean getKeepAlive() throws SocketException { 161 | try { 162 | return opts().keepAlive(); 163 | } catch (Exception x) { 164 | Net.translateToSocketException(x); 165 | return false; // Never happens 166 | } 167 | } 168 | 169 | public void setTrafficClass(int tc) throws SocketException { 170 | if (tc < 0 || tc > 255) 171 | throw new IllegalArgumentException("tc is not in range 0 -- 255"); 172 | try { 173 | opts().typeOfService(tc); 174 | } catch (Exception x) { 175 | Net.translateToSocketException(x); 176 | } 177 | } 178 | 179 | public int getTrafficClass() throws SocketException { 180 | try { 181 | return opts().typeOfService(); 182 | } catch (Exception x) { 183 | Net.translateToSocketException(x); 184 | return 0; // Never happens 185 | } 186 | } 187 | 188 | public void setReuseAddress(boolean on) 189 | throws SocketException 190 | { 191 | try { 192 | opts().reuseAddress(on); 193 | } catch (Exception x) { 194 | Net.translateToSocketException(x); 195 | } 196 | } 197 | 198 | public boolean getReuseAddress() throws SocketException { 199 | try { 200 | return opts().reuseAddress(); 201 | } catch (Exception x) { 202 | Net.translateToSocketException(x); 203 | return false; // Never happens 204 | } 205 | } 206 | 207 | public void setBroadcast(boolean on) 208 | throws SocketException 209 | { 210 | try { 211 | opts().broadcast(on); 212 | } catch (Exception x) { 213 | Net.translateToSocketException(x); 214 | } 215 | } 216 | 217 | public boolean getBroadcast() throws SocketException { 218 | try { 219 | return opts().broadcast(); 220 | } catch (Exception x) { 221 | Net.translateToSocketException(x); 222 | return false; // Never happens 223 | } 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /mocksocks-client/src/main/java/sun/nio/ch/SocketAdaptor2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Oracle designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Oracle in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 | * or visit www.oracle.com if you need additional information or have any 23 | * questions. 24 | */ 25 | 26 | package sun.nio.ch; 27 | 28 | import java.io.IOException; 29 | import java.io.InputStream; 30 | import java.io.OutputStream; 31 | import java.net.*; 32 | import java.nio.ByteBuffer; 33 | import java.nio.channels.*; 34 | import java.security.AccessController; 35 | import java.security.PrivilegedExceptionAction; 36 | 37 | 38 | // Make a socket channel look like a socket. 39 | // 40 | // The only aspects of java.net.Socket-hood that we don't attempt to emulate 41 | // here are the interrupted-I/O exceptions (which our Solaris implementations 42 | // attempt to support) and the sending of urgent data. Otherwise an adapted 43 | // socket should look enough like a real java.net.Socket to fool most of the 44 | // developers most of the time, right down to the exception message strings. 45 | // 46 | // The methods in this class are defined in exactly the same order as in 47 | // java.net.Socket so as to simplify tracking future changes to that class. 48 | // 49 | 50 | public class SocketAdaptor2 51 | extends Socket 52 | { 53 | 54 | // The channel being adapted 55 | private final SocketChannelImpl2 sc; 56 | 57 | // Option adaptor object, created on demand 58 | private volatile OptionAdaptor2 opts = null; 59 | 60 | // Timeout "option" value for reads 61 | private volatile int timeout = 0; 62 | 63 | // Traffic-class/Type-of-service 64 | private volatile int trafficClass = 0; 65 | 66 | 67 | // ## super will create a useless impl 68 | private SocketAdaptor2(SocketChannelImpl2 sc) { 69 | this.sc = sc; 70 | } 71 | 72 | public static Socket create(SocketChannelImpl2 sc) { 73 | return new SocketAdaptor2(sc); 74 | } 75 | 76 | public SocketChannel getChannel() { 77 | return sc; 78 | } 79 | 80 | // Override this method just to protect against changes in the superclass 81 | // 82 | public void connect(SocketAddress remote) throws IOException { 83 | connect(remote, 0); 84 | } 85 | 86 | public void connect(SocketAddress remote, int timeout) throws IOException { 87 | if (remote == null) 88 | throw new IllegalArgumentException("connect: The address can't be null"); 89 | if (timeout < 0) 90 | throw new IllegalArgumentException("connect: timeout can't be negative"); 91 | 92 | synchronized (sc.blockingLock()) { 93 | if (!sc.isBlocking()) 94 | throw new IllegalBlockingModeException(); 95 | 96 | try { 97 | 98 | if (timeout == 0) { 99 | sc.connect(remote); 100 | return; 101 | } 102 | 103 | // Implement timeout with a selector 104 | SelectionKey sk = null; 105 | Selector sel = null; 106 | sc.configureBlocking(false); 107 | try { 108 | if (sc.connect(remote)) 109 | return; 110 | sel = Util.getTemporarySelector(sc); 111 | sk = sc.register(sel, SelectionKey.OP_CONNECT); 112 | long to = timeout; 113 | for (;;) { 114 | if (!sc.isOpen()) 115 | throw new ClosedChannelException(); 116 | long st = System.currentTimeMillis(); 117 | int ns = sel.select(to); 118 | if (ns > 0 && 119 | sk.isConnectable() && sc.finishConnect()) 120 | break; 121 | sel.selectedKeys().remove(sk); 122 | to -= System.currentTimeMillis() - st; 123 | if (to <= 0) { 124 | try { 125 | sc.close(); 126 | } catch (IOException x) { } 127 | throw new SocketTimeoutException(); 128 | } 129 | } 130 | } finally { 131 | if (sk != null) 132 | sk.cancel(); 133 | if (sc.isOpen()) 134 | sc.configureBlocking(true); 135 | if (sel != null) 136 | Util.releaseTemporarySelector(sel); 137 | } 138 | 139 | } catch (Exception x) { 140 | Net.translateException(x, true); 141 | } 142 | } 143 | 144 | } 145 | 146 | public void bind(SocketAddress local) throws IOException { 147 | try { 148 | if (local == null) 149 | local = new InetSocketAddress(0); 150 | sc.bind(local); 151 | } catch (Exception x) { 152 | Net.translateException(x); 153 | } 154 | } 155 | 156 | public InetAddress getInetAddress() { 157 | if (!sc.isConnected()) 158 | return null; 159 | return Net.asInetSocketAddress(sc.remoteAddress()).getAddress(); 160 | } 161 | 162 | public InetAddress getLocalAddress() { 163 | if (!sc.isBound()) 164 | return new InetSocketAddress(0).getAddress(); 165 | return Net.asInetSocketAddress(sc.localAddress()).getAddress(); 166 | } 167 | 168 | public int getPort() { 169 | if (!sc.isConnected()) 170 | return 0; 171 | return Net.asInetSocketAddress(sc.remoteAddress()).getPort(); 172 | } 173 | 174 | public int getLocalPort() { 175 | if (!sc.isBound()) 176 | return -1; 177 | return Net.asInetSocketAddress(sc.localAddress()).getPort(); 178 | } 179 | 180 | private class SocketInputStream 181 | extends ChannelInputStream 182 | { 183 | private SocketInputStream() { 184 | super(sc); 185 | } 186 | 187 | protected int read(ByteBuffer bb) 188 | throws IOException 189 | { 190 | synchronized (sc.blockingLock()) { 191 | if (!sc.isBlocking()) 192 | throw new IllegalBlockingModeException(); 193 | if (timeout == 0) 194 | return sc.read(bb); 195 | 196 | // Implement timeout with a selector 197 | SelectionKey sk = null; 198 | Selector sel = null; 199 | sc.configureBlocking(false); 200 | try { 201 | int n; 202 | if ((n = sc.read(bb)) != 0) 203 | return n; 204 | sel = Util.getTemporarySelector(sc); 205 | sk = sc.register(sel, SelectionKey.OP_READ); 206 | long to = timeout; 207 | for (;;) { 208 | if (!sc.isOpen()) 209 | throw new ClosedChannelException(); 210 | long st = System.currentTimeMillis(); 211 | int ns = sel.select(to); 212 | if (ns > 0 && sk.isReadable()) { 213 | if ((n = sc.read(bb)) != 0) 214 | return n; 215 | } 216 | sel.selectedKeys().remove(sk); 217 | to -= System.currentTimeMillis() - st; 218 | if (to <= 0) 219 | throw new SocketTimeoutException(); 220 | } 221 | } finally { 222 | if (sk != null) 223 | sk.cancel(); 224 | if (sc.isOpen()) 225 | sc.configureBlocking(true); 226 | if (sel != null) 227 | Util.releaseTemporarySelector(sel); 228 | } 229 | 230 | } 231 | } 232 | } 233 | 234 | private InputStream socketInputStream = null; 235 | 236 | public InputStream getInputStream() throws IOException { 237 | if (!sc.isOpen()) 238 | throw new SocketException("Socket is closed"); 239 | if (!sc.isConnected()) 240 | throw new SocketException("Socket is not connected"); 241 | if (!sc.isInputOpen()) 242 | throw new SocketException("Socket input is shutdown"); 243 | if (socketInputStream == null) { 244 | try { 245 | socketInputStream = (InputStream)AccessController.doPrivileged( 246 | new PrivilegedExceptionAction() { 247 | public Object run() throws IOException { 248 | return new SocketInputStream(); 249 | } 250 | }); 251 | } catch (java.security.PrivilegedActionException e) { 252 | throw (IOException)e.getException(); 253 | } 254 | } 255 | return socketInputStream; 256 | } 257 | 258 | public OutputStream getOutputStream() throws IOException { 259 | if (!sc.isOpen()) 260 | throw new SocketException("Socket is closed"); 261 | if (!sc.isConnected()) 262 | throw new SocketException("Socket is not connected"); 263 | if (!sc.isOutputOpen()) 264 | throw new SocketException("Socket output is shutdown"); 265 | OutputStream os = null; 266 | try { 267 | os = (OutputStream) 268 | AccessController.doPrivileged(new PrivilegedExceptionAction() { 269 | public Object run() throws IOException { 270 | return Channels.newOutputStream(sc); 271 | } 272 | }); 273 | } catch (java.security.PrivilegedActionException e) { 274 | throw (IOException)e.getException(); 275 | } 276 | return os; 277 | } 278 | 279 | private OptionAdaptor2 opts() { 280 | if (opts == null) 281 | opts = new OptionAdaptor2(sc); 282 | return opts; 283 | } 284 | 285 | public void setTcpNoDelay(boolean on) throws SocketException { 286 | opts().setTcpNoDelay(on); 287 | } 288 | 289 | public boolean getTcpNoDelay() throws SocketException { 290 | return opts().getTcpNoDelay(); 291 | } 292 | 293 | public void setSoLinger(boolean on, int linger) throws SocketException { 294 | opts().setSoLinger(on, linger); 295 | } 296 | 297 | public int getSoLinger() throws SocketException { 298 | return opts().getSoLinger(); 299 | } 300 | 301 | public void sendUrgentData(int data) throws IOException { 302 | throw new SocketException("Urgent data not supported"); 303 | } 304 | 305 | public void setOOBInline(boolean on) throws SocketException { 306 | opts().setOOBInline(on); 307 | } 308 | 309 | public boolean getOOBInline() throws SocketException { 310 | return opts().getOOBInline(); 311 | } 312 | 313 | public void setSoTimeout(int timeout) throws SocketException { 314 | if (timeout < 0) 315 | throw new IllegalArgumentException("timeout can't be negative"); 316 | this.timeout = timeout; 317 | } 318 | 319 | public int getSoTimeout() throws SocketException { 320 | return timeout; 321 | } 322 | 323 | public void setSendBufferSize(int size) throws SocketException { 324 | opts().setSendBufferSize(size); 325 | } 326 | 327 | public int getSendBufferSize() throws SocketException { 328 | return opts().getSendBufferSize(); 329 | } 330 | 331 | public void setReceiveBufferSize(int size) throws SocketException { 332 | opts().setReceiveBufferSize(size); 333 | } 334 | 335 | public int getReceiveBufferSize() throws SocketException { 336 | return opts().getReceiveBufferSize(); 337 | } 338 | 339 | public void setKeepAlive(boolean on) throws SocketException { 340 | opts().setKeepAlive(on); 341 | } 342 | 343 | public boolean getKeepAlive() throws SocketException { 344 | return opts().getKeepAlive(); 345 | } 346 | 347 | public void setTrafficClass(int tc) throws SocketException { 348 | opts().setTrafficClass(tc); 349 | trafficClass = tc; 350 | } 351 | 352 | public int getTrafficClass() throws SocketException { 353 | int tc = opts().getTrafficClass(); 354 | if (tc < 0) { 355 | tc = trafficClass; 356 | } 357 | return tc; 358 | } 359 | 360 | public void setReuseAddress(boolean on) throws SocketException { 361 | opts().setReuseAddress(on); 362 | } 363 | 364 | public boolean getReuseAddress() throws SocketException { 365 | return opts().getReuseAddress(); 366 | } 367 | 368 | public void close() throws IOException { 369 | try { 370 | sc.close(); 371 | } catch (Exception x) { 372 | Net.translateToSocketException(x); 373 | } 374 | } 375 | 376 | public void shutdownInput() throws IOException { 377 | try { 378 | sc.shutdownInput(); 379 | } catch (Exception x) { 380 | Net.translateException(x); 381 | } 382 | } 383 | 384 | public void shutdownOutput() throws IOException { 385 | try { 386 | sc.shutdownOutput(); 387 | } catch (Exception x) { 388 | Net.translateException(x); 389 | } 390 | } 391 | 392 | public String toString() { 393 | if (sc.isConnected()) 394 | return "Socket[addr=" + getInetAddress() + 395 | ",port=" + getPort() + 396 | ",localport=" + getLocalPort() + "]"; 397 | return "Socket[unconnected]"; 398 | } 399 | 400 | public boolean isConnected() { 401 | return sc.isConnected(); 402 | } 403 | 404 | public boolean isBound() { 405 | return sc.isBound(); 406 | } 407 | 408 | public boolean isClosed() { 409 | return !sc.isOpen(); 410 | } 411 | 412 | public boolean isInputShutdown() { 413 | return !sc.isInputOpen(); 414 | } 415 | 416 | public boolean isOutputShutdown() { 417 | return !sc.isOutputOpen(); 418 | } 419 | 420 | } 421 | -------------------------------------------------------------------------------- /mocksocks-client/src/main/java/sun/nio/ch/SocketChannelImpl2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Oracle designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Oracle in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 | * or visit www.oracle.com if you need additional information or have any 23 | * questions. 24 | */ 25 | 26 | package sun.nio.ch; 27 | 28 | import java.io.FileDescriptor; 29 | import java.io.IOException; 30 | import java.net.InetAddress; 31 | import java.net.InetSocketAddress; 32 | import java.net.Socket; 33 | import java.net.SocketAddress; 34 | import java.nio.ByteBuffer; 35 | import java.nio.channels.*; 36 | import java.nio.channels.spi.SelectorProvider; 37 | 38 | 39 | /** 40 | * An implementation of SocketChannels 41 | */ 42 | 43 | class SocketChannelImpl2 44 | extends SocketChannel 45 | implements SelChImpl 46 | { 47 | 48 | // Used to make native read and write calls 49 | private static NativeDispatcher nd; 50 | 51 | // Our file descriptor object 52 | private final FileDescriptor fd; 53 | 54 | // fd value needed for dev/poll. This value will remain valid 55 | // even after the value in the file descriptor object has been set to -1 56 | private final int fdVal; 57 | 58 | // IDs of native threads doing reads and writes, for signalling 59 | private volatile long readerThread = 0; 60 | private volatile long writerThread = 0; 61 | 62 | // Lock held by current reading or connecting thread 63 | private final Object readLock = new Object(); 64 | 65 | // Lock held by current writing or connecting thread 66 | private final Object writeLock = new Object(); 67 | 68 | // Lock held by any thread that modifies the state fields declared below 69 | // DO NOT invoke a blocking I/O operation while holding this lock! 70 | private final Object stateLock = new Object(); 71 | 72 | // -- The following fields are protected by stateLock 73 | 74 | // State, increases monotonically 75 | private static final int ST_UNINITIALIZED = -1; 76 | private static final int ST_UNCONNECTED = 0; 77 | private static final int ST_PENDING = 1; 78 | private static final int ST_CONNECTED = 2; 79 | private static final int ST_KILLPENDING = 3; 80 | private static final int ST_KILLED = 4; 81 | private int state = ST_UNINITIALIZED; 82 | 83 | // Binding 84 | private SocketAddress localAddress = null; 85 | private SocketAddress remoteAddress = null; 86 | 87 | // Input/Output open 88 | private boolean isInputOpen = true; 89 | private boolean isOutputOpen = true; 90 | private boolean readyToConnect = false; 91 | 92 | // Options, created on demand 93 | private SocketOpts.IP.TCP options = null; 94 | 95 | // Socket adaptor, created on demand 96 | private Socket socket = null; 97 | 98 | // -- End of fields protected by stateLock 99 | 100 | 101 | // Constructor for normal connecting sockets 102 | // 103 | SocketChannelImpl2(SelectorProvider sp) throws IOException { 104 | super(sp); 105 | this.fd = Net.socket(true); 106 | this.fdVal = IOUtil.fdVal(fd); 107 | this.state = ST_UNCONNECTED; 108 | } 109 | 110 | // Constructor for sockets obtained from server sockets 111 | // 112 | SocketChannelImpl2(SelectorProvider sp, 113 | FileDescriptor fd, InetSocketAddress remote) 114 | throws IOException 115 | { 116 | super(sp); 117 | this.fd = fd; 118 | this.fdVal = IOUtil.fdVal(fd); 119 | this.state = ST_CONNECTED; 120 | this.remoteAddress = remote; 121 | } 122 | 123 | public Socket socket() { 124 | synchronized (stateLock) { 125 | if (socket == null) 126 | socket = SocketAdaptor2.create(this); 127 | return socket; 128 | } 129 | } 130 | 131 | private boolean ensureReadOpen() throws ClosedChannelException { 132 | synchronized (stateLock) { 133 | if (!isOpen()) 134 | throw new ClosedChannelException(); 135 | if (!isConnected()) 136 | throw new NotYetConnectedException(); 137 | if (!isInputOpen) 138 | return false; 139 | else 140 | return true; 141 | } 142 | } 143 | 144 | private void ensureWriteOpen() throws ClosedChannelException { 145 | synchronized (stateLock) { 146 | if (!isOpen()) 147 | throw new ClosedChannelException(); 148 | if (!isOutputOpen) 149 | throw new ClosedChannelException(); 150 | if (!isConnected()) 151 | throw new NotYetConnectedException(); 152 | } 153 | } 154 | 155 | private void readerCleanup() throws IOException { 156 | synchronized (stateLock) { 157 | readerThread = 0; 158 | if (state == ST_KILLPENDING) 159 | kill(); 160 | } 161 | } 162 | 163 | private void writerCleanup() throws IOException { 164 | synchronized (stateLock) { 165 | writerThread = 0; 166 | if (state == ST_KILLPENDING) 167 | kill(); 168 | } 169 | } 170 | 171 | public int read(ByteBuffer buf) throws IOException { 172 | 173 | if (buf == null) 174 | throw new NullPointerException(); 175 | 176 | synchronized (readLock) { 177 | if (!ensureReadOpen()) 178 | return -1; 179 | int n = 0; 180 | try { 181 | 182 | // Set up the interruption machinery; see 183 | // AbstractInterruptibleChannel for details 184 | // 185 | begin(); 186 | 187 | synchronized (stateLock) { 188 | if (!isOpen()) { 189 | // Either the current thread is already interrupted, so 190 | // begin() closed the channel, or another thread closed the 191 | // channel since we checked it a few bytecodes ago. In 192 | // either case the value returned here is irrelevant since 193 | // the invocation of end() in the finally block will throw 194 | // an appropriate exception. 195 | // 196 | return 0; 197 | 198 | } 199 | 200 | // Save this thread so that it can be signalled on those 201 | // platforms that require it 202 | // 203 | readerThread = NativeThread.current(); 204 | } 205 | 206 | // Between the previous test of isOpen() and the return of the 207 | // IOUtil.read invocation below, this channel might be closed 208 | // or this thread might be interrupted. We rely upon the 209 | // implicit synchronization point in the kernel read() call to 210 | // make sure that the right thing happens. In either case the 211 | // implCloseSelectableChannel method is ultimately invoked in 212 | // some other thread, so there are three possibilities: 213 | // 214 | // - implCloseSelectableChannel() invokes nd.preClose() 215 | // before this thread invokes read(), in which case the 216 | // read returns immediately with either EOF or an error, 217 | // the latter of which will cause an IOException to be 218 | // thrown. 219 | // 220 | // - implCloseSelectableChannel() invokes nd.preClose() after 221 | // this thread is blocked in read(). On some operating 222 | // systems (e.g., Solaris and Windows) this causes the read 223 | // to return immediately with either EOF or an error 224 | // indication. 225 | // 226 | // - implCloseSelectableChannel() invokes nd.preClose() after 227 | // this thread is blocked in read() but the operating 228 | // system (e.g., Linux) doesn't support preemptive close, 229 | // so implCloseSelectableChannel() proceeds to signal this 230 | // thread, thereby causing the read to return immediately 231 | // with IOStatus.INTERRUPTED. 232 | // 233 | // In all three cases the invocation of end() in the finally 234 | // clause will notice that the channel has been closed and 235 | // throw an appropriate exception (AsynchronousCloseException 236 | // or ClosedByInterruptException) if necessary. 237 | // 238 | // *There is A fourth possibility. implCloseSelectableChannel() 239 | // invokes nd.preClose(), signals reader/writer thred and quickly 240 | // moves on to nd.close() in kill(), which does a real close. 241 | // Then a third thread accepts a new connection, opens file or 242 | // whatever that causes the released "fd" to be recycled. All 243 | // above happens just between our last isOpen() check and the 244 | // next kernel read reached, with the recycled "fd". The solution 245 | // is to postpone the real kill() if there is a reader or/and 246 | // writer thread(s) over there "waiting", leave the cleanup/kill 247 | // to the reader or writer thread. (the preClose() still happens 248 | // so the connection gets cut off as usual). 249 | // 250 | // For socket channels there is the additional wrinkle that 251 | // asynchronous shutdown works much like asynchronous close, 252 | // except that the channel is shutdown rather than completely 253 | // closed. This is analogous to the first two cases above, 254 | // except that the shutdown operation plays the role of 255 | // nd.preClose(). 256 | for (;;) { 257 | n = IOUtil.read(fd, buf, -1, nd, readLock); 258 | if ((n == IOStatus.INTERRUPTED) && isOpen()) { 259 | // The system call was interrupted but the channel 260 | // is still open, so retry 261 | continue; 262 | } 263 | return IOStatus.normalize(n); 264 | } 265 | 266 | } finally { 267 | readerCleanup(); // Clear reader thread 268 | // The end method, which is defined in our superclass 269 | // AbstractInterruptibleChannel, resets the interruption 270 | // machinery. If its argument is true then it returns 271 | // normally; otherwise it checks the interrupt and open state 272 | // of this channel and throws an appropriate exception if 273 | // necessary. 274 | // 275 | // So, if we actually managed to do any I/O in the above try 276 | // block then we pass true to the end method. We also pass 277 | // true if the channel was in non-blocking mode when the I/O 278 | // operation was initiated but no data could be transferred; 279 | // this prevents spurious exceptions from being thrown in the 280 | // rare event that a channel is closed or a thread is 281 | // interrupted at the exact moment that a non-blocking I/O 282 | // request is made. 283 | // 284 | end(n > 0 || (n == IOStatus.UNAVAILABLE)); 285 | 286 | // Extra case for socket channels: Asynchronous shutdown 287 | // 288 | synchronized (stateLock) { 289 | if ((n <= 0) && (!isInputOpen)) 290 | return IOStatus.EOF; 291 | } 292 | 293 | assert IOStatus.check(n); 294 | 295 | } 296 | } 297 | } 298 | 299 | private long read0(ByteBuffer[] bufs) throws IOException { 300 | if (bufs == null) 301 | throw new NullPointerException(); 302 | synchronized (readLock) { 303 | if (!ensureReadOpen()) 304 | return -1; 305 | long n = 0; 306 | try { 307 | begin(); 308 | synchronized (stateLock) { 309 | if (!isOpen()) 310 | return 0; 311 | readerThread = NativeThread.current(); 312 | } 313 | 314 | for (;;) { 315 | n = IOUtil.read(fd, bufs, nd); 316 | if ((n == IOStatus.INTERRUPTED) && isOpen()) 317 | continue; 318 | return IOStatus.normalize(n); 319 | } 320 | } finally { 321 | readerCleanup(); 322 | end(n > 0 || (n == IOStatus.UNAVAILABLE)); 323 | synchronized (stateLock) { 324 | if ((n <= 0) && (!isInputOpen)) 325 | return IOStatus.EOF; 326 | } 327 | assert IOStatus.check(n); 328 | } 329 | } 330 | } 331 | 332 | public long read(ByteBuffer[] dsts, int offset, int length) 333 | throws IOException 334 | { 335 | if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) 336 | throw new IndexOutOfBoundsException(); 337 | // ## Fix IOUtil.write so that we can avoid this array copy 338 | return read0(Util.subsequence(dsts, offset, length)); 339 | } 340 | 341 | public int write(ByteBuffer buf) throws IOException { 342 | if (buf == null) 343 | throw new NullPointerException(); 344 | synchronized (writeLock) { 345 | ensureWriteOpen(); 346 | int n = 0; 347 | try { 348 | begin(); 349 | synchronized (stateLock) { 350 | if (!isOpen()) 351 | return 0; 352 | writerThread = NativeThread.current(); 353 | } 354 | for (;;) { 355 | n = IOUtil.write(fd, buf, -1, nd, writeLock); 356 | if ((n == IOStatus.INTERRUPTED) && isOpen()) 357 | continue; 358 | return IOStatus.normalize(n); 359 | } 360 | } finally { 361 | writerCleanup(); 362 | end(n > 0 || (n == IOStatus.UNAVAILABLE)); 363 | synchronized (stateLock) { 364 | if ((n <= 0) && (!isOutputOpen)) 365 | throw new AsynchronousCloseException(); 366 | } 367 | assert IOStatus.check(n); 368 | } 369 | } 370 | } 371 | 372 | public long write0(ByteBuffer[] bufs) throws IOException { 373 | if (bufs == null) 374 | throw new NullPointerException(); 375 | synchronized (writeLock) { 376 | ensureWriteOpen(); 377 | long n = 0; 378 | try { 379 | begin(); 380 | synchronized (stateLock) { 381 | if (!isOpen()) 382 | return 0; 383 | writerThread = NativeThread.current(); 384 | } 385 | for (;;) { 386 | n = IOUtil.write(fd, bufs, nd); 387 | if ((n == IOStatus.INTERRUPTED) && isOpen()) 388 | continue; 389 | return IOStatus.normalize(n); 390 | } 391 | } finally { 392 | writerCleanup(); 393 | end((n > 0) || (n == IOStatus.UNAVAILABLE)); 394 | synchronized (stateLock) { 395 | if ((n <= 0) && (!isOutputOpen)) 396 | throw new AsynchronousCloseException(); 397 | } 398 | assert IOStatus.check(n); 399 | } 400 | } 401 | } 402 | 403 | public long write(ByteBuffer[] srcs, int offset, int length) 404 | throws IOException 405 | { 406 | if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) 407 | throw new IndexOutOfBoundsException(); 408 | // ## Fix IOUtil.write so that we can avoid this array copy 409 | return write0(Util.subsequence(srcs, offset, length)); 410 | } 411 | 412 | protected void implConfigureBlocking(boolean block) throws IOException { 413 | IOUtil.configureBlocking(fd, block); 414 | } 415 | 416 | public SocketOpts options() { 417 | synchronized (stateLock) { 418 | if (options == null) { 419 | SocketOptsImpl.Dispatcher d 420 | = new SocketOptsImpl.Dispatcher() { 421 | int getInt(int opt) throws IOException { 422 | return Net.getIntOption(fd, opt); 423 | } 424 | void setInt(int opt, int arg) 425 | throws IOException 426 | { 427 | Net.setIntOption(fd, opt, arg); 428 | } 429 | }; 430 | options = new SocketOptsImpl.IP.TCP(d); 431 | } 432 | return options; 433 | } 434 | } 435 | 436 | public boolean isBound() { 437 | synchronized (stateLock) { 438 | if (state == ST_CONNECTED) 439 | return true; 440 | return localAddress != null; 441 | } 442 | } 443 | 444 | public SocketAddress localAddress() { 445 | synchronized (stateLock) { 446 | if (state == ST_CONNECTED && 447 | (localAddress == null || 448 | ((InetSocketAddress)localAddress).getAddress().isAnyLocalAddress())) { 449 | // Socket was not bound before connecting or 450 | // Socket was bound with an "anyLocalAddress" 451 | localAddress = Net.localAddress(fd); 452 | } 453 | return localAddress; 454 | } 455 | } 456 | 457 | public SocketAddress remoteAddress() { 458 | synchronized (stateLock) { 459 | return remoteAddress; 460 | } 461 | } 462 | 463 | public void bind(SocketAddress local) throws IOException { 464 | synchronized (readLock) { 465 | synchronized (writeLock) { 466 | synchronized (stateLock) { 467 | ensureOpenAndUnconnected(); 468 | if (localAddress != null) 469 | throw new AlreadyBoundException(); 470 | InetSocketAddress isa = Net.checkAddress(local); 471 | Net.bind(fd, isa.getAddress(), isa.getPort()); 472 | localAddress = Net.localAddress(fd); 473 | } 474 | } 475 | } 476 | } 477 | 478 | public boolean isConnected() { 479 | synchronized (stateLock) { 480 | return (state == ST_CONNECTED); 481 | } 482 | } 483 | 484 | public boolean isConnectionPending() { 485 | synchronized (stateLock) { 486 | return (state == ST_PENDING); 487 | } 488 | } 489 | 490 | void ensureOpenAndUnconnected() throws IOException { // package-private 491 | synchronized (stateLock) { 492 | if (!isOpen()) 493 | throw new ClosedChannelException(); 494 | if (state == ST_CONNECTED) 495 | throw new AlreadyConnectedException(); 496 | if (state == ST_PENDING) 497 | throw new ConnectionPendingException(); 498 | } 499 | } 500 | 501 | public boolean connect(SocketAddress sa) throws IOException { 502 | int trafficClass = 0; // ## Pick up from options 503 | int localPort = 0; 504 | 505 | synchronized (readLock) { 506 | synchronized (writeLock) { 507 | ensureOpenAndUnconnected(); 508 | InetSocketAddress isa = Net.checkAddress(sa); 509 | SecurityManager sm = System.getSecurityManager(); 510 | if (sm != null) 511 | sm.checkConnect(isa.getAddress().getHostAddress(), 512 | isa.getPort()); 513 | synchronized (blockingLock()) { 514 | int n = 0; 515 | try { 516 | try { 517 | begin(); 518 | synchronized (stateLock) { 519 | if (!isOpen()) { 520 | return false; 521 | } 522 | readerThread = NativeThread.current(); 523 | } 524 | for (;;) { 525 | InetAddress ia = isa.getAddress(); 526 | if (ia.isAnyLocalAddress()) 527 | ia = InetAddress.getLocalHost(); 528 | n = Net.connect(fd, 529 | ia, 530 | isa.getPort(), 531 | trafficClass); 532 | if ( (n == IOStatus.INTERRUPTED) 533 | && isOpen()) 534 | continue; 535 | break; 536 | } 537 | } finally { 538 | readerCleanup(); 539 | end((n > 0) || (n == IOStatus.UNAVAILABLE)); 540 | assert IOStatus.check(n); 541 | } 542 | } catch (IOException x) { 543 | // If an exception was thrown, close the channel after 544 | // invoking end() so as to avoid bogus 545 | // AsynchronousCloseExceptions 546 | close(); 547 | throw x; 548 | } 549 | synchronized (stateLock) { 550 | remoteAddress = isa; 551 | if (n > 0) { 552 | 553 | // Connection succeeded; disallow further 554 | // invocation 555 | state = ST_CONNECTED; 556 | return true; 557 | } 558 | // If nonblocking and no exception then connection 559 | // pending; disallow another invocation 560 | if (!isBlocking()) 561 | state = ST_PENDING; 562 | else 563 | assert false; 564 | } 565 | } 566 | return false; 567 | } 568 | } 569 | } 570 | 571 | public boolean finishConnect() throws IOException { 572 | synchronized (readLock) { 573 | synchronized (writeLock) { 574 | synchronized (stateLock) { 575 | if (!isOpen()) 576 | throw new ClosedChannelException(); 577 | if (state == ST_CONNECTED) 578 | return true; 579 | if (state != ST_PENDING) 580 | throw new NoConnectionPendingException(); 581 | } 582 | int n = 0; 583 | try { 584 | try { 585 | begin(); 586 | synchronized (blockingLock()) { 587 | synchronized (stateLock) { 588 | if (!isOpen()) { 589 | return false; 590 | } 591 | readerThread = NativeThread.current(); 592 | } 593 | if (!isBlocking()) { 594 | for (;;) { 595 | n = checkConnect(fd, false, 596 | readyToConnect); 597 | if ( (n == IOStatus.INTERRUPTED) 598 | && isOpen()) 599 | continue; 600 | break; 601 | } 602 | } else { 603 | for (;;) { 604 | n = checkConnect(fd, true, 605 | readyToConnect); 606 | if (n == 0) { 607 | // Loop in case of 608 | // spurious notifications 609 | continue; 610 | } 611 | if ( (n == IOStatus.INTERRUPTED) 612 | && isOpen()) 613 | continue; 614 | break; 615 | } 616 | } 617 | } 618 | } finally { 619 | synchronized (stateLock) { 620 | readerThread = 0; 621 | if (state == ST_KILLPENDING) { 622 | kill(); 623 | // poll()/getsockopt() does not report 624 | // error (throws exception, with n = 0) 625 | // on Linux platform after dup2 and 626 | // signal-wakeup. Force n to 0 so the 627 | // end() can throw appropriate exception 628 | n = 0; 629 | } 630 | } 631 | end((n > 0) || (n == IOStatus.UNAVAILABLE)); 632 | assert IOStatus.check(n); 633 | } 634 | } catch (IOException x) { 635 | // If an exception was thrown, close the channel after 636 | // invoking end() so as to avoid bogus 637 | // AsynchronousCloseExceptions 638 | close(); 639 | throw x; 640 | } 641 | if (n > 0) { 642 | synchronized (stateLock) { 643 | state = ST_CONNECTED; 644 | } 645 | return true; 646 | } 647 | return false; 648 | } 649 | } 650 | } 651 | 652 | public final static int SHUT_RD = 0; 653 | public final static int SHUT_WR = 1; 654 | public final static int SHUT_RDWR = 2; 655 | 656 | public void shutdownInput() throws IOException { 657 | synchronized (stateLock) { 658 | if (!isOpen()) 659 | throw new ClosedChannelException(); 660 | isInputOpen = false; 661 | shutdown(fd, SHUT_RD); 662 | if (readerThread != 0) 663 | NativeThread.signal(readerThread); 664 | } 665 | } 666 | 667 | public void shutdownOutput() throws IOException { 668 | synchronized (stateLock) { 669 | if (!isOpen()) 670 | throw new ClosedChannelException(); 671 | isOutputOpen = false; 672 | shutdown(fd, SHUT_WR); 673 | if (writerThread != 0) 674 | NativeThread.signal(writerThread); 675 | } 676 | } 677 | 678 | public boolean isInputOpen() { 679 | synchronized (stateLock) { 680 | return isInputOpen; 681 | } 682 | } 683 | 684 | public boolean isOutputOpen() { 685 | synchronized (stateLock) { 686 | return isOutputOpen; 687 | } 688 | } 689 | 690 | // AbstractInterruptibleChannel synchronizes invocations of this method 691 | // using AbstractInterruptibleChannel.closeLock, and also ensures that this 692 | // method is only ever invoked once. Before we get to this method, isOpen 693 | // (which is volatile) will have been set to false. 694 | // 695 | protected void implCloseSelectableChannel() throws IOException { 696 | synchronized (stateLock) { 697 | isInputOpen = false; 698 | isOutputOpen = false; 699 | 700 | // Close the underlying file descriptor and dup it to a known fd 701 | // that's already closed. This prevents other operations on this 702 | // channel from using the old fd, which might be recycled in the 703 | // meantime and allocated to an entirely different channel. 704 | // 705 | nd.preClose(fd); 706 | 707 | // Signal native threads, if needed. If a target thread is not 708 | // currently blocked in an I/O operation then no harm is done since 709 | // the signal handler doesn't actually do anything. 710 | // 711 | if (readerThread != 0) 712 | NativeThread.signal(readerThread); 713 | 714 | if (writerThread != 0) 715 | NativeThread.signal(writerThread); 716 | 717 | // If this channel is not registered then it's safe to close the fd 718 | // immediately since we know at this point that no thread is 719 | // blocked in an I/O operation upon the channel and, since the 720 | // channel is marked closed, no thread will start another such 721 | // operation. If this channel is registered then we don't close 722 | // the fd since it might be in use by a selector. In that case 723 | // closing this channel caused its keys to be cancelled, so the 724 | // last selector to deregister a key for this channel will invoke 725 | // kill() to close the fd. 726 | // 727 | if (!isRegistered()) 728 | kill(); 729 | } 730 | } 731 | 732 | public void kill() throws IOException { 733 | synchronized (stateLock) { 734 | if (state == ST_KILLED) 735 | return; 736 | if (state == ST_UNINITIALIZED) { 737 | state = ST_KILLED; 738 | return; 739 | } 740 | assert !isOpen() && !isRegistered(); 741 | 742 | // Postpone the kill if there is a waiting reader 743 | // or writer thread. See the comments in read() for 744 | // more detailed explanation. 745 | if (readerThread == 0 && writerThread == 0) { 746 | nd.close(fd); 747 | state = ST_KILLED; 748 | } else { 749 | state = ST_KILLPENDING; 750 | } 751 | } 752 | } 753 | 754 | /** 755 | * Translates native poll revent ops into a ready operation ops 756 | */ 757 | public boolean translateReadyOps(int ops, int initialOps, 758 | SelectionKeyImpl sk) { 759 | int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes 760 | int oldOps = sk.nioReadyOps(); 761 | int newOps = initialOps; 762 | 763 | if ((ops & PollArrayWrapper.POLLNVAL) != 0) { 764 | // This should only happen if this channel is pre-closed while a 765 | // selection operation is in progress 766 | // ## Throw an error if this channel has not been pre-closed 767 | return false; 768 | } 769 | 770 | if ((ops & (PollArrayWrapper.POLLERR 771 | | PollArrayWrapper.POLLHUP)) != 0) { 772 | newOps = intOps; 773 | sk.nioReadyOps(newOps); 774 | // No need to poll again in checkConnect, 775 | // the error will be detected there 776 | readyToConnect = true; 777 | return (newOps & ~oldOps) != 0; 778 | } 779 | 780 | if (((ops & PollArrayWrapper.POLLIN) != 0) && 781 | ((intOps & SelectionKey.OP_READ) != 0) && 782 | (state == ST_CONNECTED)) 783 | newOps |= SelectionKey.OP_READ; 784 | 785 | if (((ops & PollArrayWrapper.POLLCONN) != 0) && 786 | ((intOps & SelectionKey.OP_CONNECT) != 0) && 787 | ((state == ST_UNCONNECTED) || (state == ST_PENDING))) { 788 | newOps |= SelectionKey.OP_CONNECT; 789 | readyToConnect = true; 790 | } 791 | 792 | if (((ops & PollArrayWrapper.POLLOUT) != 0) && 793 | ((intOps & SelectionKey.OP_WRITE) != 0) && 794 | (state == ST_CONNECTED)) 795 | newOps |= SelectionKey.OP_WRITE; 796 | 797 | sk.nioReadyOps(newOps); 798 | return (newOps & ~oldOps) != 0; 799 | } 800 | 801 | public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) { 802 | return translateReadyOps(ops, sk.nioReadyOps(), sk); 803 | } 804 | 805 | public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) { 806 | return translateReadyOps(ops, 0, sk); 807 | } 808 | 809 | /** 810 | * Translates an interest operation set into a native poll event set 811 | */ 812 | public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) { 813 | int newOps = 0; 814 | if ((ops & SelectionKey.OP_READ) != 0) 815 | newOps |= PollArrayWrapper.POLLIN; 816 | if ((ops & SelectionKey.OP_WRITE) != 0) 817 | newOps |= PollArrayWrapper.POLLOUT; 818 | if ((ops & SelectionKey.OP_CONNECT) != 0) 819 | newOps |= PollArrayWrapper.POLLCONN; 820 | sk.selector.putEventOps(sk, newOps); 821 | } 822 | 823 | public FileDescriptor getFD() { 824 | return fd; 825 | } 826 | 827 | public int getFDVal() { 828 | return fdVal; 829 | } 830 | 831 | public String toString() { 832 | StringBuffer sb = new StringBuffer(); 833 | sb.append(this.getClass().getSuperclass().getName()); 834 | sb.append('['); 835 | if (!isOpen()) 836 | sb.append("closed"); 837 | else { 838 | synchronized (stateLock) { 839 | switch (state) { 840 | case ST_UNCONNECTED: 841 | sb.append("unconnected"); 842 | break; 843 | case ST_PENDING: 844 | sb.append("connection-pending"); 845 | break; 846 | case ST_CONNECTED: 847 | sb.append("connected"); 848 | if (!isInputOpen) 849 | sb.append(" ishut"); 850 | if (!isOutputOpen) 851 | sb.append(" oshut"); 852 | break; 853 | } 854 | if (localAddress() != null) { 855 | sb.append(" local="); 856 | sb.append(localAddress().toString()); 857 | } 858 | if (remoteAddress() != null) { 859 | sb.append(" remote="); 860 | sb.append(remoteAddress().toString()); 861 | } 862 | } 863 | } 864 | sb.append(']'); 865 | return sb.toString(); 866 | } 867 | 868 | 869 | // -- Native methods -- 870 | 871 | private static native int checkConnect(FileDescriptor fd, 872 | boolean block, boolean ready) 873 | throws IOException; 874 | 875 | private static native void shutdown(FileDescriptor fd, int how) 876 | throws IOException; 877 | 878 | static { 879 | Util.load(); 880 | nd = new SocketDispatcher(); 881 | } 882 | 883 | } 884 | -------------------------------------------------------------------------------- /mocksocks-client/src/main/java/sun/nio/ch/SocksProxySocketChannel.java: -------------------------------------------------------------------------------- 1 | package sun.nio.ch; 2 | 3 | import java.io.IOException; 4 | import java.net.Inet6Address; 5 | import java.net.InetSocketAddress; 6 | import java.net.SocketAddress; 7 | import java.nio.ByteBuffer; 8 | import java.nio.channels.IllegalBlockingModeException; 9 | import java.nio.channels.spi.SelectorProvider; 10 | 11 | /** 12 | * @author yihua.huang@dianping.com 13 | */ 14 | public class SocksProxySocketChannel extends SocketChannelImpl { 15 | 16 | public static final byte CMD_CONNECT = (byte) 0x01; 17 | public static final byte SCHEME_NO_AUTH = (byte) 0x00; 18 | public static final byte RESERVED_BYTE = (byte) 0x00; 19 | public static final byte ATYP_IPV4 = (byte) 0x01; 20 | public static final byte ATYP_IPV6 = (byte) 0x04; 21 | private SocketAddress remote; 22 | 23 | private static final int DEFAULT_ENCODER_BUFFER_SIZE = 1024; 24 | 25 | private static final byte SOCKS_PROTOCAL_VERSION = (byte) 0x05; 26 | 27 | public SocksProxySocketChannel(SelectorProvider sp) throws IOException { 28 | super(sp); 29 | } 30 | 31 | @Override 32 | public SocketAddress remoteAddress() { 33 | if (remote != null) { 34 | return remote; 35 | } else { 36 | return super.remoteAddress(); 37 | } 38 | } 39 | 40 | @Override 41 | public boolean connect(SocketAddress sa) throws IOException { 42 | this.remote = sa; 43 | boolean connect; 44 | SocketAddress socksProxy = getSocksProxy(); 45 | if (socksProxy != null) { 46 | boolean blocking = isBlocking(); 47 | if (!blocking) { 48 | // change to blocking mode for easy 49 | try { 50 | configureBlocking(true); 51 | connect = socksConnect(socksProxy); 52 | if (!blocking) { 53 | configureBlocking(false); 54 | } 55 | } catch (IllegalBlockingModeException e) { 56 | System.err.println("Can't set proxy for " + sa); 57 | connect = super.connect(sa); 58 | } 59 | } else { 60 | connect = socksConnect(socksProxy); 61 | } 62 | } else { 63 | connect = super.connect(sa); 64 | } 65 | return connect; 66 | } 67 | 68 | private boolean socksConnect(SocketAddress socksProxy) throws IOException { 69 | boolean connect; 70 | connect = super.connect(socksProxy); 71 | if (!connect) { 72 | throw new IOException("Connect to proxy " + socksProxy + " fail!"); 73 | } 74 | ByteBuffer byteBuffer = ByteBuffer.allocate(DEFAULT_ENCODER_BUFFER_SIZE); 75 | sendSockInitRequest(byteBuffer); 76 | sendSockCmdRequest(byteBuffer); 77 | // TODO:handle response 78 | return connect; 79 | } 80 | 81 | private void sendSockCmdRequest(ByteBuffer byteBuffer) throws IOException { 82 | byteBuffer.clear(); 83 | byteBuffer.put(SOCKS_PROTOCAL_VERSION); 84 | // TODO:add more cmd support 85 | byteBuffer.put(CMD_CONNECT); 86 | byteBuffer.put(RESERVED_BYTE); 87 | InetSocketAddress inetSocketAddress = Net.asInetSocketAddress(remote); 88 | if (inetSocketAddress.getAddress() instanceof Inet6Address) { 89 | byteBuffer.put(ATYP_IPV6); 90 | } else { 91 | byteBuffer.put(ATYP_IPV4); 92 | } 93 | byteBuffer.put(inetSocketAddress.getAddress().getAddress()); 94 | byteBuffer.putShort((short) (0xffff & inetSocketAddress.getPort())); 95 | byteBuffer.flip(); 96 | write(byteBuffer); 97 | read(byteBuffer); 98 | } 99 | 100 | private void sendSockInitRequest(ByteBuffer byteBuffer) throws IOException { 101 | byteBuffer.clear(); 102 | byteBuffer.put(SOCKS_PROTOCAL_VERSION); 103 | byteBuffer.put((byte) 0x01); // size of authschemes 104 | byteBuffer.put(SCHEME_NO_AUTH); 105 | byteBuffer.flip(); 106 | write(byteBuffer); 107 | byteBuffer.clear(); 108 | read(byteBuffer); 109 | } 110 | 111 | protected SocketAddress getSocksProxy() { 112 | SocketAddress proxySocketAddress; 113 | String host = System.getProperty("socksProxyHost"); 114 | String port = System.getProperty("socksProxyPort"); 115 | if (host == null || port == null) { 116 | return null; 117 | } 118 | try { 119 | proxySocketAddress = new InetSocketAddress(host, Integer.parseInt(port)); 120 | } catch (Exception e) { 121 | return null; 122 | } 123 | return proxySocketAddress; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /mocksocks-gui/asserts/icons.graffle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ApplicationVersion 6 | 7 | com.omnigroup.OmniGrafflePro 8 | 139.16.0.171715 9 | 10 | CreationDate 11 | 2013-10-30 01:43:31 +0000 12 | Creator 13 | 黄 亿华 14 | GraphDocumentVersion 15 | 8 16 | GuidesLocked 17 | NO 18 | GuidesVisible 19 | YES 20 | ImageCounter 21 | 1 22 | LinksVisible 23 | NO 24 | MagnetsVisible 25 | NO 26 | MasterSheets 27 | 28 | ModificationDate 29 | 2013-10-30 01:44:42 +0000 30 | Modifier 31 | 黄 亿华 32 | NotesVisible 33 | NO 34 | OriginVisible 35 | NO 36 | PageBreaks 37 | YES 38 | PrintInfo 39 | 40 | NSBottomMargin 41 | 42 | float 43 | 41 44 | 45 | NSHorizonalPagination 46 | 47 | coded 48 | BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG 49 | 50 | NSLeftMargin 51 | 52 | float 53 | 18 54 | 55 | NSPaperSize 56 | 57 | size 58 | {594.99997329711914, 842} 59 | 60 | NSPrintReverseOrientation 61 | 62 | int 63 | 0 64 | 65 | NSRightMargin 66 | 67 | float 68 | 18 69 | 70 | NSTopMargin 71 | 72 | float 73 | 18 74 | 75 | 76 | ReadOnly 77 | NO 78 | Sheets 79 | 80 | 81 | ActiveLayerIndex 82 | 0 83 | AutoAdjust 84 | 85 | BackgroundGraphic 86 | 87 | Bounds 88 | {{0, 0}, {558.99997329711914, 783}} 89 | Class 90 | SolidGraphic 91 | ID 92 | 2 93 | Style 94 | 95 | shadow 96 | 97 | Draws 98 | NO 99 | 100 | stroke 101 | 102 | Draws 103 | NO 104 | 105 | 106 | 107 | BaseZoom 108 | 0 109 | CanvasOrigin 110 | {0, 0} 111 | ColumnAlign 112 | 1 113 | ColumnSpacing 114 | 36 115 | DisplayScale 116 | 1 0/72 in = 1 0/72 in 117 | GraphicsList 118 | 119 | 120 | Bounds 121 | {{232.99997329711914, 91}, {46.500015258789062, 45}} 122 | Class 123 | ShapedGraphic 124 | ID 125 | 28 126 | Shape 127 | Circle 128 | Style 129 | 130 | fill 131 | 132 | Color 133 | 134 | b 135 | 0.213175 136 | g 137 | 0.182128 138 | r 139 | 1 140 | 141 | 142 | stroke 143 | 144 | Draws 145 | NO 146 | 147 | 148 | Text 149 | 150 | VerticalPad 151 | 0 152 | 153 | 154 | 155 | GridInfo 156 | 157 | HPages 158 | 1 159 | KeepToScale 160 | 161 | Layers 162 | 163 | 164 | Lock 165 | NO 166 | Name 167 | 图层 1 168 | Print 169 | YES 170 | View 171 | YES 172 | 173 | 174 | LayoutInfo 175 | 176 | Animate 177 | NO 178 | circoMinDist 179 | 18 180 | circoSeparation 181 | 0.0 182 | layoutEngine 183 | dot 184 | neatoSeparation 185 | 0.0 186 | twopiSeparation 187 | 0.0 188 | 189 | Orientation 190 | 2 191 | PrintOnePage 192 | 193 | RowAlign 194 | 1 195 | RowSpacing 196 | 36 197 | SheetTitle 198 | 版面 1 199 | UniqueID 200 | 1 201 | VPages 202 | 1 203 | 204 | 205 | ActiveLayerIndex 206 | 0 207 | AutoAdjust 208 | 209 | BackgroundGraphic 210 | 211 | Bounds 212 | {{0, 0}, {558.99997329711914, 783}} 213 | Class 214 | SolidGraphic 215 | ID 216 | 2 217 | Style 218 | 219 | shadow 220 | 221 | Draws 222 | NO 223 | 224 | stroke 225 | 226 | Draws 227 | NO 228 | 229 | 230 | 231 | BaseZoom 232 | 0 233 | CanvasOrigin 234 | {0, 0} 235 | ColumnAlign 236 | 1 237 | ColumnSpacing 238 | 36 239 | DisplayScale 240 | 1 0/72 in = 1.0000 in 241 | GraphicsList 242 | 243 | 244 | Bounds 245 | {{232.99997329711914, 91}, {46.500015258789062, 45}} 246 | Class 247 | ShapedGraphic 248 | ID 249 | 28 250 | Shape 251 | Circle 252 | Style 253 | 254 | fill 255 | 256 | Color 257 | 258 | b 259 | 0.726756 260 | g 261 | 0.733663 262 | r 263 | 0.949028 264 | 265 | 266 | stroke 267 | 268 | Draws 269 | NO 270 | 271 | 272 | Text 273 | 274 | VerticalPad 275 | 0 276 | 277 | 278 | 279 | GridInfo 280 | 281 | HPages 282 | 1 283 | KeepToScale 284 | 285 | Layers 286 | 287 | 288 | Lock 289 | NO 290 | Name 291 | 图层 1 292 | Print 293 | YES 294 | View 295 | YES 296 | 297 | 298 | LayoutInfo 299 | 300 | Animate 301 | NO 302 | circoMinDist 303 | 18 304 | circoSeparation 305 | 0.0 306 | layoutEngine 307 | dot 308 | neatoSeparation 309 | 0.0 310 | twopiSeparation 311 | 0.0 312 | 313 | Orientation 314 | 2 315 | PrintOnePage 316 | 317 | RowAlign 318 | 1 319 | RowSpacing 320 | 36 321 | SheetTitle 322 | 版面 2 323 | UniqueID 324 | 2 325 | VPages 326 | 1 327 | 328 | 329 | SmartAlignmentGuidesActive 330 | YES 331 | SmartDistanceGuidesActive 332 | YES 333 | UseEntirePage 334 | 335 | WindowInfo 336 | 337 | CurrentSheet 338 | 1 339 | ExpandedCanvases 340 | 341 | Frame 342 | {{373, 77}, {693, 801}} 343 | ListView 344 | 345 | OutlineWidth 346 | 142 347 | RightSidebar 348 | 349 | ShowRuler 350 | 351 | Sidebar 352 | 353 | SidebarWidth 354 | 120 355 | VisibleRegion 356 | {{0, 0}, {558, 662}} 357 | Zoom 358 | 1 359 | ZoomValues 360 | 361 | 362 | 版面 1 363 | 1 364 | 1 365 | 366 | 367 | 版面 2 368 | 1 369 | 1 370 | 371 | 372 | 373 | 374 | 375 | -------------------------------------------------------------------------------- /mocksocks-gui/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | mocksocks 7 | com.dianping 8 | 0.0.2-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | com.dianping 13 | mocksocks-gui 14 | 0.0.2-SNAPSHOT 15 | 16 | 17 | 18 | com.jgoodies 19 | jgoodies-forms 20 | 1.6.0 21 | 22 | 23 | com.jgoodies 24 | jgoodies-common 25 | 1.4.0 26 | 27 | 28 | com.jgoodies 29 | jgoodies-binding 30 | 2.7.0 31 | 32 | 33 | com.dianping 34 | mocksocks-transport 35 | ${project.version} 36 | 37 | 38 | com.intellij 39 | forms_rt 40 | 7.0.3 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.codehaus.mojo 48 | ideauidesigner-maven-plugin 49 | 50 | 51 | 52 | javac2 53 | 54 | 55 | 56 | 57 | 58 | true 59 | true 60 | true 61 | 62 | 63 | 64 | org.apache.maven.plugins 65 | maven-dependency-plugin 66 | 67 | 68 | copy-dependencies 69 | package 70 | 71 | copy-dependencies 72 | 73 | 74 | ${project.build.directory}/lib 75 | false 76 | false 77 | true 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | org.apache.maven.plugins 86 | maven-jar-plugin 87 | 88 | 89 | 90 | true 91 | lib/ 92 | com.dianping.mocksocks.gui.gui.MocksocksDashboard 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/java/com/dianping/mocksocks/gui/data/ConnectionStatusListModel.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.gui.data; 2 | 3 | import com.dianping.mocksocks.transport.Connection; 4 | import com.dianping.mocksocks.transport.monitor.ConnectionMonitor; 5 | import com.dianping.mocksocks.transport.rules.filter.Filter; 6 | 7 | import javax.swing.*; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * @author yihua.huang@dianping.com 13 | */ 14 | public class ConnectionStatusListModel extends AbstractListModel { 15 | 16 | private List display = new ArrayList(); 17 | 18 | private List connectionStatuses = new ArrayList(); 19 | 20 | private List> filters = new ArrayList>(); 21 | 22 | public ConnectionStatusListModel(final int refreshTime) { 23 | new Thread(new Runnable() { 24 | @Override 25 | public void run() { 26 | while (true) { 27 | try { 28 | Thread.sleep(refreshTime); 29 | } catch (InterruptedException e) { 30 | e.printStackTrace(); 31 | } 32 | update(); 33 | } 34 | } 35 | 36 | }).start(); 37 | } 38 | 39 | public synchronized void update() { 40 | display.clear(); 41 | connectionStatuses.clear(); 42 | connectionLoop: 43 | for (Connection connection : ConnectionMonitor.getInstance().status()) { 44 | if (filters.size() > 0) { 45 | for (Filter filter : filters) { 46 | if (!filter.preserve(connection)) { 47 | continue connectionLoop; 48 | } 49 | } 50 | } 51 | connectionStatuses.add(connection); 52 | display.add(connection.toString()); 53 | } 54 | fireContentsChanged(this, 0, display.size()); 55 | } 56 | 57 | @Override 58 | public int getSize() { 59 | return display.size(); 60 | } 61 | 62 | public void setFilters(List> filters) { 63 | this.filters = filters; 64 | } 65 | 66 | public void setFilter(Filter filter) { 67 | this.filters.clear(); 68 | filters.add(filter); 69 | } 70 | 71 | @Override 72 | public Object getElementAt(int index) { 73 | try { 74 | return display.get(index); 75 | } catch (ArrayIndexOutOfBoundsException e) { 76 | return null; 77 | } 78 | } 79 | 80 | public Connection getConnectionStatus(int index) { 81 | return connectionStatuses.get(index); 82 | } 83 | 84 | public void clear() { 85 | display.clear(); 86 | fireContentsChanged(this, 0, 1); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/java/com/dianping/mocksocks/gui/data/MessageListModel.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.gui.data; 2 | 3 | import com.dianping.mocksocks.transport.Connection; 4 | 5 | import javax.swing.*; 6 | 7 | /** 8 | * @author yihua.huang@dianping.com 9 | */ 10 | public class MessageListModel extends AbstractListModel { 11 | 12 | private Connection connection; 13 | 14 | public MessageListModel(Connection connection) { 15 | this.connection = connection; 16 | } 17 | 18 | @Override 19 | public int getSize() { 20 | return connection.getMessages().size(); 21 | } 22 | 23 | @Override 24 | public Object getElementAt(int index) { 25 | return connection.getMessages().get(index); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/java/com/dianping/mocksocks/gui/gui/Menu.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.gui.gui; 2 | 3 | import javax.swing.*; 4 | import java.awt.event.ActionEvent; 5 | import java.awt.event.ActionListener; 6 | import java.awt.event.KeyEvent; 7 | 8 | /** 9 | * @author yihua.huang@dianping.com 10 | */ 11 | public class Menu extends JMenuBar { 12 | 13 | private JMenu proxy; 14 | 15 | private JMenuItem startProxy; 16 | 17 | private JMenuItem stopProxy; 18 | 19 | private JCheckBoxMenuItem macOsProxy; 20 | 21 | private JMenu rules; 22 | 23 | private JMenuItem redirectRules; 24 | 25 | public Menu() { 26 | proxy = new JMenu("Proxy"); 27 | startProxy = new JMenuItem("Start", KeyEvent.VK_S); 28 | stopProxy = new JMenuItem("Stop", KeyEvent.VK_T); 29 | macOsProxy = new JCheckBoxMenuItem("Mac OX proxy",false); 30 | macOsProxy.addActionListener(new ActionListener() { 31 | @Override 32 | public void actionPerformed(ActionEvent e) { 33 | //networksetup -setwebproxy 34 | //http://hints.macworld.com/article.php?story=2003101617122867 35 | } 36 | }); 37 | proxy.add(startProxy); 38 | proxy.add(stopProxy); 39 | proxy.add(macOsProxy); 40 | this.add(proxy); 41 | rules = new JMenu("Rule"); 42 | redirectRules = new JMenuItem("Redirect", KeyEvent.VK_R); 43 | rules.add(redirectRules); 44 | this.add(rules); 45 | 46 | } 47 | 48 | public JMenu getRules() { 49 | return rules; 50 | } 51 | 52 | public JMenuItem getRedirectRules() { 53 | return redirectRules; 54 | } 55 | 56 | public JMenu getProxy() { 57 | return proxy; 58 | } 59 | 60 | public JMenuItem getStartProxy() { 61 | return startProxy; 62 | } 63 | 64 | public JMenuItem getStopProxy() { 65 | return stopProxy; 66 | } 67 | 68 | public JCheckBoxMenuItem getMacOsProxy() { 69 | return macOsProxy; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/java/com/dianping/mocksocks/gui/gui/MessageDetailDialog.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/java/com/dianping/mocksocks/gui/gui/MessageDetailDialog.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.gui.gui; 2 | 3 | import com.dianping.mocksocks.transport.Transmit; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.awt.event.KeyEvent; 9 | 10 | public class MessageDetailDialog extends JDialog { 11 | private JPanel contentPane; 12 | private JButton buttonOK; 13 | private JButton buttonCancel; 14 | private JTabbedPane tabbedPane1; 15 | private JEditorPane editorRequest; 16 | private JEditorPane editorResponse; 17 | private JTabbedPane requestTab; 18 | private JEditorPane editorRequestHex; 19 | private JTabbedPane responseTab; 20 | private JEditorPane editorResponseHex; 21 | private Transmit transmit; 22 | 23 | public MessageDetailDialog() { 24 | setContentPane(contentPane); 25 | setModal(true); 26 | getRootPane().setDefaultButton(buttonOK); 27 | 28 | buttonOK.addActionListener(new ActionListener() { 29 | public void actionPerformed(ActionEvent e) { 30 | onOK(); 31 | } 32 | }); 33 | buttonCancel.addActionListener(new ActionListener() { 34 | public void actionPerformed(ActionEvent e) { 35 | onOK(); 36 | } 37 | }); 38 | contentPane.registerKeyboardAction(new ActionListener() { 39 | public void actionPerformed(ActionEvent e) { 40 | onCancel(); 41 | } 42 | }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 43 | } 44 | 45 | public void setTransmit(Transmit transmit) { 46 | this.transmit = transmit; 47 | if (transmit.getRequest() != null) { 48 | editorRequest.setText(transmit.getRequest().textOutput()); 49 | editorRequestHex.setText(transmit.getRequest().hexOutput()); 50 | } else { 51 | editorRequest.setText(""); 52 | editorRequestHex.setText(""); 53 | } 54 | if (transmit.getResponse() != null) { 55 | editorResponse.setText(transmit.getResponse().textOutput()); 56 | editorResponseHex.setText(transmit.getResponse().hexOutput()); 57 | } else { 58 | editorResponse.setText(""); 59 | editorResponseHex.setText(""); 60 | } 61 | } 62 | 63 | private void onCancel() { 64 | // add your code here if necessary 65 | dispose(); 66 | } 67 | 68 | private void onOK() { 69 | // add your code here 70 | dispose(); 71 | } 72 | 73 | public static void main(String[] args) { 74 | MessageDetailDialog dialog = new MessageDetailDialog(); 75 | dialog.pack(); 76 | dialog.setVisible(true); 77 | System.exit(0); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/java/com/dianping/mocksocks/gui/gui/MocksocksDashboard.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/java/com/dianping/mocksocks/gui/gui/MocksocksDashboard.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.gui.gui; 2 | 3 | import com.dianping.mocksocks.gui.data.ConnectionStatusListModel; 4 | import com.dianping.mocksocks.gui.data.MessageListModel; 5 | import com.dianping.mocksocks.transport.Transmit; 6 | import com.dianping.mocksocks.transport.Connection; 7 | import com.dianping.mocksocks.transport.monitor.config.Configs; 8 | import com.dianping.mocksocks.transport.monitor.ConnectionMonitor; 9 | import com.dianping.mocksocks.transport.rules.filter.ConnectionStatusHostFilter; 10 | import com.dianping.mocksocks.transport.proxy.SocksProxy; 11 | 12 | import javax.swing.*; 13 | import java.awt.event.*; 14 | 15 | /** 16 | * @author yihua.huang@dianping.com 17 | */ 18 | public class MocksocksDashboard { 19 | public static final int REFRESH_TIME = 1000; 20 | private JList listConnection; 21 | private JPanel panel; 22 | private JButton startButton; 23 | private JButton stopButton; 24 | private JButton clearButton; 25 | private JComboBox comboBox; 26 | private JTextField textField1; 27 | private JButton filterButton; 28 | private JTabbedPane tabbedPane1; 29 | private JList listMessage; 30 | private JToolBar toolBar; 31 | private Menu menu; 32 | private RedirectRulesDialog redirectRulesDialog; 33 | private MessageDetailDialog messageDetailDialog; 34 | 35 | private ConnectionStatusListModel listModel; 36 | final SocksProxy socksProxy = new SocksProxy(); 37 | 38 | public MocksocksDashboard() { 39 | listModel = new ConnectionStatusListModel(REFRESH_TIME); 40 | listConnection.setModel(listModel); 41 | initToolbar(); 42 | initFilter(); 43 | menu = new Menu(); 44 | menu.getRedirectRules().addActionListener(new ActionListener() { 45 | @Override 46 | public void actionPerformed(ActionEvent e) { 47 | getRedirectRulesDialog().setVisible(true); 48 | } 49 | }); 50 | listConnection.addMouseListener(new MouseAdapter() { 51 | @Override 52 | public void mouseClicked(MouseEvent e) { 53 | if (e.getClickCount() > 1 && e.getButton() == MouseEvent.BUTTON1) { 54 | Connection connection = listModel.getConnectionStatus(listConnection.getSelectedIndex()); 55 | MessageListModel defaultListModel = new MessageListModel(connection); 56 | listMessage.setModel(defaultListModel); 57 | tabbedPane1.setSelectedIndex(1); 58 | } 59 | } 60 | }); 61 | listMessage.addMouseListener(new MouseAdapter() { 62 | @Override 63 | public void mouseClicked(MouseEvent e) { 64 | if (e.getClickCount() > 1 && e.getButton() == MouseEvent.BUTTON1) { 65 | Transmit transmit = (Transmit) listMessage.getSelectedValue(); 66 | getMessageDetailDialog().setTransmit(transmit); 67 | getMessageDetailDialog().setVisible(true); 68 | } 69 | } 70 | }); 71 | frame.setContentPane(panel); 72 | frame.setJMenuBar(menu); 73 | frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 74 | frame.pack(); 75 | frame.addWindowListener(new ClosingHandler()); 76 | 77 | startProxy(); 78 | } 79 | 80 | private void initFilter() { 81 | filterButton.addActionListener(new ActionListener() { 82 | @Override 83 | public void actionPerformed(ActionEvent e) { 84 | fireFilter(); 85 | } 86 | }); 87 | textField1.addKeyListener(new KeyAdapter() { 88 | @Override 89 | public void keyTyped(KeyEvent e) { 90 | if (e.getKeyChar() == '\n') { 91 | fireFilter(); 92 | } 93 | } 94 | }); 95 | } 96 | 97 | private void initToolbar() { 98 | startButton.addActionListener(new ActionListener() { 99 | @Override 100 | public void actionPerformed(ActionEvent e) { 101 | if (!socksProxy.isRunning()) { 102 | if (!startProxy()) { 103 | return; 104 | } 105 | } 106 | Configs.getInstance().setRecord(true); 107 | startButton.setVisible(false); 108 | stopButton.setVisible(true); 109 | stopButton.grabFocus(); 110 | } 111 | }); 112 | stopButton.addActionListener(new ActionListener() { 113 | @Override 114 | public void actionPerformed(ActionEvent e) { 115 | Configs.getInstance().setRecord(false); 116 | stopButton.setVisible(false); 117 | startButton.setVisible(true); 118 | startButton.grabFocus(); 119 | } 120 | }); 121 | clearButton.addActionListener(new ActionListener() { 122 | @Override 123 | public void actionPerformed(ActionEvent e) { 124 | listModel.clear(); 125 | ConnectionMonitor.getInstance().clear(); 126 | } 127 | }); 128 | } 129 | 130 | private boolean startProxy() { 131 | try { 132 | socksProxy.start(); 133 | return true; 134 | } catch (Exception e) { 135 | JOptionPane.showMessageDialog(panel, e); 136 | startButton.setVisible(true); 137 | stopButton.setVisible(false); 138 | return false; 139 | } 140 | } 141 | 142 | public RedirectRulesDialog getRedirectRulesDialog() { 143 | if (redirectRulesDialog == null) { 144 | redirectRulesDialog = new RedirectRulesDialog(); 145 | redirectRulesDialog.pack(); 146 | redirectRulesDialog.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); 147 | } 148 | return redirectRulesDialog; 149 | } 150 | 151 | public MessageDetailDialog getMessageDetailDialog() { 152 | if (messageDetailDialog == null) { 153 | messageDetailDialog = new MessageDetailDialog(); 154 | messageDetailDialog.pack(); 155 | messageDetailDialog.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); 156 | } 157 | return messageDetailDialog; 158 | } 159 | 160 | private void fireFilter() { 161 | String filterType = (String) comboBox.getSelectedItem(); 162 | String filterValue = textField1.getText(); 163 | if ("host".equals(filterType)) { 164 | try { 165 | listModel.setFilter(new ConnectionStatusHostFilter(filterValue)); 166 | } catch (Exception ex) { 167 | ex.printStackTrace(); 168 | JOptionPane.showConfirmDialog(panel, ex); 169 | } 170 | } 171 | } 172 | 173 | class ClosingHandler extends WindowAdapter { 174 | @Override 175 | public void windowClosing(WindowEvent e) { 176 | socksProxy.stop(); 177 | } 178 | } 179 | 180 | private JFrame frame = new JFrame("MockSocks"); 181 | 182 | public void addClosingHandler(WindowAdapter closingHandler) { 183 | frame.addWindowListener(closingHandler); 184 | } 185 | 186 | public void show(){ 187 | frame.setVisible(true); 188 | } 189 | 190 | public static void main(String[] args) { 191 | MocksocksDashboard mocksocksDashboard = new MocksocksDashboard(); 192 | mocksocksDashboard.show(); 193 | } 194 | 195 | private void createUIComponents() { 196 | // TODO: place custom component creation code here 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/java/com/dianping/mocksocks/gui/gui/RedirectRulesDialog.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 |
104 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/java/com/dianping/mocksocks/gui/gui/RedirectRulesDialog.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.gui.gui; 2 | 3 | import com.dianping.mocksocks.transport.monitor.config.RulesDao; 4 | import com.dianping.mocksocks.transport.rules.RulesContainer; 5 | 6 | import javax.swing.*; 7 | import java.awt.event.*; 8 | import java.sql.SQLException; 9 | 10 | public class RedirectRulesDialog extends JDialog { 11 | private JPanel contentPane; 12 | private JButton buttonOK; 13 | private JButton buttonCancel; 14 | private JTextArea textArea1; 15 | 16 | public RedirectRulesDialog() { 17 | try { 18 | String redirectRules = new RulesDao().getByType(RulesDao.TYPE_REDIRECT); 19 | textArea1.setText(redirectRules); 20 | } catch (SQLException e) { 21 | e.printStackTrace(); 22 | } 23 | setContentPane(contentPane); 24 | setModal(true); 25 | getRootPane().setDefaultButton(buttonOK); 26 | 27 | buttonCancel.addActionListener(new ActionListener() { 28 | public void actionPerformed(ActionEvent e) { 29 | onCancel(); 30 | } 31 | }); 32 | 33 | // call onCancel() when cross is clicked 34 | setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); 35 | addWindowListener(new WindowAdapter() { 36 | public void windowClosing(WindowEvent e) { 37 | onCancel(); 38 | } 39 | }); 40 | 41 | // call onCancel() on ESCAPE 42 | contentPane.registerKeyboardAction(new ActionListener() { 43 | public void actionPerformed(ActionEvent e) { 44 | onCancel(); 45 | } 46 | }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 47 | buttonOK.addActionListener(new ActionListener() { 48 | @Override 49 | public void actionPerformed(ActionEvent e) { 50 | try { 51 | RulesContainer.getInstance().setRedirectRules(RulesContainer.parse(textArea1.getText())); 52 | new RulesDao().setByType(RulesDao.TYPE_REDIRECT, textArea1.getText()); 53 | dispose(); 54 | } catch (Exception ex) { 55 | ex.printStackTrace(); 56 | JOptionPane.showMessageDialog(contentPane, ex); 57 | } 58 | } 59 | }); 60 | } 61 | 62 | private void onOK() { 63 | // add your code here 64 | dispose(); 65 | } 66 | 67 | private void onCancel() { 68 | // add your code here if necessary 69 | dispose(); 70 | } 71 | 72 | public static void main(String[] args) { 73 | RedirectRulesDialog dialog = new RedirectRulesDialog(); 74 | dialog.pack(); 75 | dialog.setVisible(true); 76 | System.exit(0); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /mocksocks-gui/src/main/resources/icon/record-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/mocksocks-gui/src/main/resources/icon/record-start.png -------------------------------------------------------------------------------- /mocksocks-gui/src/main/resources/icon/record-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/mocksocks-gui/src/main/resources/icon/record-stop.png -------------------------------------------------------------------------------- /mocksocks-gui/src/main/resources/icon/status-clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4craft/mocksocks/b9a1ac672db242acb6461a1345f1ab1d469a0a71/mocksocks-gui/src/main/resources/icon/status-clear.png -------------------------------------------------------------------------------- /mocksocks-junit/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | mocksocks 7 | com.dianping 8 | 0.0.2-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | com.dianping 13 | mocksocks-junit 14 | 0.0.2-SNAPSHOT 15 | 16 | 17 | 18 | junit 19 | junit 20 | 4.4 21 | provided 22 | 23 | 24 | mocksock-proxy 25 | com.dianping 26 | 0.0.2-SNAPSHOT 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /mocksocks-junit/src/main/java/com/dianping/mocksocks/junit/MockSocksClassRunner.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.junit; 2 | 3 | import com.dianping.mocksocks.proxy.Proxy; 4 | import org.junit.internal.runners.InitializationError; 5 | import org.junit.internal.runners.JUnit4ClassRunner; 6 | import org.junit.runner.notification.RunNotifier; 7 | 8 | /** 9 | * @author yihua.huang@dianping.com 10 | */ 11 | public class MockSocksClassRunner extends JUnit4ClassRunner { 12 | public MockSocksClassRunner(Class klass) throws InitializationError { 13 | super(klass); 14 | } 15 | 16 | @Override 17 | public void run(RunNotifier notifier) { 18 | setProxy(); 19 | super.run(notifier); 20 | } 21 | 22 | private static void setProxy() { 23 | System.setProperty("socksProxyHost", "127.0.0.1"); 24 | System.setProperty("socksProxyPort", "40310"); 25 | } 26 | 27 | private static void startProxy(String cacheFileName) { 28 | Proxy proxy = null; 29 | // proxy.start(); 30 | // proxy.loadCache(cacheFileName); 31 | } 32 | 33 | public static void init(Object object) { 34 | setProxy(); 35 | //TODO:file 36 | startProxy(""); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mocksocks-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | mocksocks 7 | com.dianping 8 | 0.0.2-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | com.dianping 13 | mocksocks-sample 14 | 0.0.2-SNAPSHOT 15 | 16 | 17 | 18 | org.jboss.netty 19 | netty 20 | 3.2.9.Final 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /mocksocks-sample/src/main/java/com/dianping/mocksocks/sample/telnet/TelnetClient.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.sample.telnet; 17 | 18 | import org.jboss.netty.bootstrap.ClientBootstrap; 19 | import org.jboss.netty.channel.Channel; 20 | import org.jboss.netty.channel.ChannelFuture; 21 | import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; 22 | 23 | import java.io.BufferedReader; 24 | import java.io.IOException; 25 | import java.io.InputStreamReader; 26 | import java.net.InetSocketAddress; 27 | import java.util.concurrent.Executors; 28 | 29 | /** 30 | * Simplistic telnet client. 31 | */ 32 | public class TelnetClient { 33 | 34 | private final String host; 35 | private final int port; 36 | 37 | public TelnetClient(String host, int port) { 38 | this.host = host; 39 | this.port = port; 40 | } 41 | 42 | public void run() throws IOException { 43 | // Configure the client. 44 | ClientBootstrap bootstrap = new ClientBootstrap( 45 | new NioClientSocketChannelFactory( 46 | Executors.newCachedThreadPool(), 47 | Executors.newCachedThreadPool())); 48 | 49 | // Configure the pipeline factory. 50 | bootstrap.setPipelineFactory(new TelnetClientPipelineFactory()); 51 | 52 | // Start the connection attempt. 53 | ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); 54 | 55 | // Wait until the connection attempt succeeds or fails. 56 | Channel channel = future.awaitUninterruptibly().getChannel(); 57 | if (!future.isSuccess()) { 58 | future.getCause().printStackTrace(); 59 | bootstrap.releaseExternalResources(); 60 | return; 61 | } 62 | 63 | // Read commands from the stdin. 64 | ChannelFuture lastWriteFuture = null; 65 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 66 | for (;;) { 67 | String line = in.readLine(); 68 | if (line == null) { 69 | break; 70 | } 71 | 72 | // Sends the received line to the server. 73 | lastWriteFuture = channel.write(line + "\r\n"); 74 | 75 | // If user typed the 'bye' command, wait until the server closes 76 | // the connection. 77 | if ("bye".equals(line.toLowerCase())) { 78 | channel.getCloseFuture().awaitUninterruptibly(); 79 | break; 80 | } 81 | } 82 | 83 | // Wait until all messages are flushed before closing the channel. 84 | if (lastWriteFuture != null) { 85 | lastWriteFuture.awaitUninterruptibly(); 86 | } 87 | 88 | // Close the connection. Make sure the close operation ends because 89 | // all I/O operations are asynchronous in Netty. 90 | channel.close().awaitUninterruptibly(); 91 | 92 | // Shut down all thread pools to exit. 93 | bootstrap.releaseExternalResources(); 94 | } 95 | 96 | public static void main(String[] args) throws Exception { 97 | // System.clearProperty("socksProxyHost"); 98 | // Print usage if no argument is specified. 99 | if (args.length != 2) { 100 | System.err.println( 101 | "Usage: " + TelnetClient.class.getSimpleName() + 102 | " "); 103 | return; 104 | } 105 | 106 | // Parse options. 107 | String host = args[0]; 108 | int port = Integer.parseInt(args[1]); 109 | 110 | new TelnetClient(host, port).run(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /mocksocks-sample/src/main/java/com/dianping/mocksocks/sample/telnet/TelnetClientHandler.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.sample.telnet; 17 | 18 | import org.jboss.netty.channel.*; 19 | 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | 23 | /** 24 | * Handles a client-side channel. 25 | */ 26 | public class TelnetClientHandler extends SimpleChannelUpstreamHandler { 27 | 28 | private static final Logger logger = Logger.getLogger( 29 | TelnetClientHandler.class.getName()); 30 | 31 | @Override 32 | public void handleUpstream( 33 | ChannelHandlerContext ctx, ChannelEvent e) throws Exception { 34 | if (e instanceof ChannelStateEvent) { 35 | logger.info(e.toString()); 36 | } 37 | super.handleUpstream(ctx, e); 38 | } 39 | 40 | @Override 41 | public void messageReceived( 42 | ChannelHandlerContext ctx, MessageEvent e) { 43 | // Print out the line received from the server. 44 | System.err.println(e.getMessage()); 45 | } 46 | 47 | @Override 48 | public void exceptionCaught( 49 | ChannelHandlerContext ctx, ExceptionEvent e) { 50 | logger.log( 51 | Level.WARNING, 52 | "Unexpected exception from downstream.", 53 | e.getCause()); 54 | e.getChannel().close(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /mocksocks-sample/src/main/java/com/dianping/mocksocks/sample/telnet/TelnetClientPipelineFactory.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.sample.telnet; 17 | 18 | import org.jboss.netty.channel.ChannelPipeline; 19 | import org.jboss.netty.channel.ChannelPipelineFactory; 20 | import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; 21 | import org.jboss.netty.handler.codec.frame.Delimiters; 22 | import org.jboss.netty.handler.codec.string.StringDecoder; 23 | import org.jboss.netty.handler.codec.string.StringEncoder; 24 | 25 | import static org.jboss.netty.channel.Channels.pipeline; 26 | 27 | /** 28 | * Creates a newly configured {@link ChannelPipeline} for a new channel. 29 | */ 30 | public class TelnetClientPipelineFactory implements 31 | ChannelPipelineFactory { 32 | 33 | public ChannelPipeline getPipeline() throws Exception { 34 | // Create a default pipeline implementation. 35 | ChannelPipeline pipeline = pipeline(); 36 | 37 | // Add the text line codec combination first, 38 | pipeline.addLast("framer", new DelimiterBasedFrameDecoder( 39 | 8192, Delimiters.lineDelimiter())); 40 | pipeline.addLast("decoder", new StringDecoder()); 41 | pipeline.addLast("encoder", new StringEncoder()); 42 | 43 | // and then business logic. 44 | pipeline.addLast("handler", new TelnetClientHandler()); 45 | 46 | return pipeline; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mocksocks-transport/README.md: -------------------------------------------------------------------------------- 1 | how to set proxy for NIO 2 | [http://blog.tsunanet.net/2010/08/java-nio-and-overengineering.html](http://blog.tsunanet.net/2010/08/java-nio-and-overengineering.html) 3 | 4 | [http://hllvm.group.iteye.com/group/topic/37814](http://hllvm.group.iteye.com/group/topic/37814) 5 | 6 | javaagent做织入:参考`com.google.monitoring.runtime.instrumentation.AllocationInstrumenter` 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /mocksocks-transport/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | mocksocks 7 | com.dianping 8 | 0.0.2-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | mocksocks-transport 13 | 14 | 15 | 16 | io.netty 17 | netty 18 | 3.7.0.Final 19 | 20 | 21 | org.resthub 22 | hessian 23 | 4.0.8 24 | 25 | 26 | org.apache.commons 27 | commons-lang3 28 | 3.1 29 | 30 | 31 | commons-dbutils 32 | commons-dbutils 33 | 1.5 34 | 35 | 36 | com.h2database 37 | h2 38 | 1.3.174 39 | 40 | 41 | 42 | junit 43 | junit 44 | 4.4 45 | test 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /mocksocks-transport/sql/rules.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE Rules( 2 | Type varchar(20) PRIMARY KEY, 3 | Content varchar(5000), 4 | ); 5 | 6 | CREATE TABLE Message( 7 | ID INT PRIMARY KEY auto_increment, 8 | Body blob 9 | ); 10 | 11 | CREATE TABLE Exchange( 12 | ID INT PRIMARY KEY auto_increment, 13 | Connection 14 | 15 | ); -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/Connection.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport; 2 | 3 | import com.dianping.mocksocks.transport.monitor.StatusFormatter; 4 | import com.dianping.mocksocks.transport.monitor.config.Configs; 5 | import org.jboss.netty.buffer.ChannelBuffer; 6 | import org.jboss.netty.channel.Channel; 7 | 8 | import java.net.InetSocketAddress; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * @author yihua.huang@dianping.com 14 | */ 15 | public class Connection { 16 | 17 | private long startTime; 18 | 19 | private long endTime; 20 | 21 | private int bytesSend; 22 | 23 | private int bytesReceive; 24 | 25 | private Channel channel; 26 | 27 | private String status; 28 | 29 | private List messages = new ArrayList(); 30 | 31 | private Transmit current; 32 | 33 | public static final String SUCCESS = "success"; 34 | 35 | public static final String FAIL = "fail"; 36 | 37 | public static final String CONNECTED = "connected"; 38 | 39 | private String protocol; 40 | 41 | public Connection(Channel channel) { 42 | this.channel = channel; 43 | } 44 | 45 | public Connection() { 46 | } 47 | 48 | public long getStartTime() { 49 | return startTime; 50 | } 51 | 52 | public Connection start() { 53 | this.startTime = System.currentTimeMillis(); 54 | this.status = CONNECTED; 55 | return this; 56 | } 57 | 58 | public void setStartTime(long startTime) { 59 | this.startTime = startTime; 60 | } 61 | 62 | public long getEndTime() { 63 | return endTime; 64 | } 65 | 66 | public void setEndTime(long endTime) { 67 | this.endTime = endTime; 68 | } 69 | 70 | public int getBytesSend() { 71 | return bytesSend; 72 | } 73 | 74 | public synchronized void setBytesSend(int bytesSend) { 75 | this.bytesSend = bytesSend; 76 | } 77 | 78 | public synchronized void addBytesSend(long bytesSend) { 79 | this.bytesSend += bytesSend; 80 | } 81 | 82 | public int getBytesReceive() { 83 | return bytesReceive; 84 | } 85 | 86 | public synchronized void setBytesReceive(int bytesReceive) { 87 | this.bytesReceive = bytesReceive; 88 | } 89 | 90 | public synchronized void request(ChannelBuffer channelBuffer) { 91 | if (!Configs.getInstance().isRecord()) { 92 | return; 93 | } 94 | this.bytesSend += channelBuffer.readableBytes(); 95 | if (current == null) { 96 | current = new Transmit(); 97 | messages.add(current); 98 | current.setRequest(new Message(channelBuffer, Message.MessageType.Request, protocol)); 99 | } else if (current.getRequest() == null) { 100 | current.setRequest(new Message(channelBuffer, Message.MessageType.Request, protocol)); 101 | } else if (current.getRequest() != null && current.getResponse() == null) { 102 | current.getRequest().addChannelBuffer(channelBuffer); 103 | } else if (current.getResponse() != null) { 104 | messages.add(current); 105 | } 106 | } 107 | 108 | public synchronized void response(ChannelBuffer channelBuffer) { 109 | if (!Configs.getInstance().isRecord()) { 110 | return; 111 | } 112 | this.bytesReceive += channelBuffer.readableBytes(); 113 | if (current == null || current.getRequest() == null) { 114 | } else if (current.getRequest() != null && current.getResponse() == null) { 115 | current.setResponse(new Message(channelBuffer, Message.MessageType.Response, protocol)); 116 | } else if (current.getResponse() != null) { 117 | current.getResponse().addChannelBuffer(channelBuffer); 118 | } 119 | } 120 | 121 | public synchronized void addBytesReceive(long bytesReceive) { 122 | this.bytesReceive += bytesReceive; 123 | } 124 | 125 | public String getStatus() { 126 | return status; 127 | } 128 | 129 | public List getMessages() { 130 | return messages; 131 | } 132 | 133 | public InetSocketAddress getAddress() { 134 | return (InetSocketAddress) channel.getRemoteAddress(); 135 | } 136 | 137 | public Connection setStatus(String status) { 138 | this.status = status; 139 | return this; 140 | } 141 | 142 | public Connection close() { 143 | this.status = "closed"; 144 | endTime = System.currentTimeMillis(); 145 | return this; 146 | } 147 | 148 | public void setChannel(Channel channel) { 149 | this.channel = channel; 150 | } 151 | 152 | public String getProtocol() { 153 | return protocol; 154 | } 155 | 156 | public void setProtocol(String protocol) { 157 | this.protocol = protocol; 158 | } 159 | 160 | @Override 161 | public String toString() { 162 | return "Connection{remote=" + channel.getRemoteAddress() + ",startTime=" 163 | + StatusFormatter.formatTimeStamp(startTime) + ", endTime=" + StatusFormatter.formatTimeStamp(endTime) 164 | + ", timeCost=" + (endTime > 0 ? StatusFormatter.formatTimePeriod(endTime - startTime) : 0) 165 | + ", bytesSend=" + StatusFormatter.formatBytes(bytesSend) + ", bytesReceive=" 166 | + StatusFormatter.formatBytes(bytesReceive) + ", status=" + status + '}'; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/Message.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.jboss.netty.buffer.ChannelBuffer; 5 | import org.jboss.netty.buffer.ChannelBuffers; 6 | 7 | import java.nio.ByteBuffer; 8 | import java.nio.charset.Charset; 9 | 10 | /** 11 | * @author yihua.huang@dianping.com 12 | */ 13 | public class Message { 14 | 15 | public static final int BYTES_PER_LINE = 16; 16 | private String protocol; 17 | private Charset charset = Charset.defaultCharset(); 18 | 19 | public enum MessageType { 20 | Request, Response; 21 | } 22 | 23 | private ChannelBuffer channelBuffer; 24 | 25 | private MessageType type; 26 | 27 | public Message(ChannelBuffer channelBuffer, MessageType type) { 28 | this.channelBuffer = channelBuffer; 29 | this.type = type; 30 | } 31 | 32 | public Message(ChannelBuffer channelBuffer, MessageType type, String protocol) { 33 | this.protocol = protocol; 34 | this.channelBuffer = channelBuffer; 35 | this.type = type; 36 | } 37 | 38 | public String getProtocol() { 39 | return protocol; 40 | } 41 | 42 | public ChannelBuffer getChannelBuffer() { 43 | return channelBuffer; 44 | } 45 | 46 | public MessageType getType() { 47 | return type; 48 | } 49 | 50 | public void setProtocol(String protocol) { 51 | this.protocol = protocol; 52 | } 53 | 54 | public void addChannelBuffer(ChannelBuffer channelBuffer) { 55 | this.channelBuffer = ChannelBuffers.wrappedBuffer(this.channelBuffer, channelBuffer); 56 | } 57 | 58 | public void setChannelBuffer(ChannelBuffer channelBuffer) { 59 | this.channelBuffer = channelBuffer; 60 | } 61 | 62 | public void setType(MessageType type) { 63 | this.type = type; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return "Message{" + "protocol='" + protocol + '\'' + ", channelBuffer=" 69 | + StringUtils.substringBefore(textOutput(), "\n") + ", type=" + type + '}'; 70 | } 71 | 72 | public String textOutput() { 73 | return channelBuffer.toString("utf-8"); 74 | } 75 | 76 | public Charset getCharset() { 77 | return charset; 78 | } 79 | 80 | public void setCharset(Charset charset) { 81 | this.charset = charset; 82 | } 83 | 84 | public String hexOutput() { 85 | StringBuilder accum = new StringBuilder(); 86 | int size = channelBuffer.readableBytes(); 87 | int lineCount = (size / BYTES_PER_LINE) + 1; 88 | ByteBuffer byteBuffer = ByteBuffer.allocate(BYTES_PER_LINE); 89 | for (int i = 0; i < lineCount; i++) { 90 | byteBuffer.clear(); 91 | int length = size - i * BYTES_PER_LINE; 92 | if (length > BYTES_PER_LINE) { 93 | length = BYTES_PER_LINE; 94 | } 95 | accum.append(StringUtils.leftPad(Integer.toHexString(0xff & i), 4, "0").toUpperCase() + " "); 96 | for (int j = 0; j < length; j++) { 97 | byte b = channelBuffer.readByte(); 98 | byteBuffer.put(b); 99 | accum.append(StringUtils.leftPad(Integer.toHexString(0xff & b), 2, "0").toUpperCase() + " "); 100 | } 101 | if (length < BYTES_PER_LINE) { 102 | for (int j = 0; j < BYTES_PER_LINE - length; j++) { 103 | accum.append(" "); 104 | } 105 | } 106 | byteBuffer.flip(); 107 | accum.append(charset.decode(byteBuffer)); 108 | accum.append("\n"); 109 | } 110 | return accum.toString(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/Proxy.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport; 2 | 3 | /** 4 | * @author yihua.huang@dianping.com 5 | */ 6 | public interface Proxy { 7 | 8 | public void start(); 9 | 10 | public void stop(); 11 | 12 | public void loadCache(String cacheFile); 13 | 14 | public boolean isRunning(); 15 | } 16 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/Transmit.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport; 2 | 3 | /** 4 | * @author yihua.huang@dianping.com 5 | */ 6 | public class Transmit { 7 | 8 | private Message request; 9 | 10 | private Message response; 11 | 12 | public Message getRequest() { 13 | return request; 14 | } 15 | 16 | public void setRequest(Message request) { 17 | this.request = request; 18 | } 19 | 20 | public Message getResponse() { 21 | return response; 22 | } 23 | 24 | public void setResponse(Message response) { 25 | this.response = response; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return "Transmit{" + 31 | "request=" + request + 32 | ", response=" + response + 33 | '}'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/dao/BaseDao.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.dao; 2 | 3 | import org.apache.commons.dbutils.DbUtils; 4 | import org.h2.jdbcx.JdbcDataSource; 5 | 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | 8 | /** 9 | * @author yihua.huang@dianping.com 10 | */ 11 | public class BaseDao { 12 | 13 | private static AtomicBoolean connected = new AtomicBoolean(false); 14 | 15 | private static JdbcDataSource jdbcDataSource; 16 | 17 | protected void initDatabase() { 18 | if (connected.compareAndSet(false, true)) { 19 | try { 20 | DbUtils.loadDriver("org.h2.Driver"); 21 | jdbcDataSource = new JdbcDataSource(); 22 | jdbcDataSource.setURL("jdbc:h2:~/test2"); 23 | jdbcDataSource.setUser("sa"); 24 | jdbcDataSource.setPassword(""); 25 | } catch (Exception e) { 26 | connected.compareAndSet(true, false); 27 | } 28 | } 29 | } 30 | 31 | protected JdbcDataSource getJdbcDataSource() { 32 | return jdbcDataSource; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/handler/OutPutHandler.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.handler; 2 | 3 | import org.jboss.netty.buffer.ChannelBuffer; 4 | import org.jboss.netty.channel.ChannelHandlerContext; 5 | import org.jboss.netty.channel.MessageEvent; 6 | import org.jboss.netty.channel.SimpleChannelUpstreamHandler; 7 | 8 | import java.nio.ByteBuffer; 9 | 10 | /** 11 | * @author yihua.huang@dianping.com 12 | */ 13 | public class OutPutHandler extends SimpleChannelUpstreamHandler{ 14 | 15 | @Override 16 | public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { 17 | if (!(e.getMessage() instanceof ChannelBuffer)){ 18 | System.out.println(e.getMessage()); 19 | } 20 | ChannelBuffer channelBuffer = (ChannelBuffer) e.getMessage(); 21 | ByteBuffer byteBuffer = ByteBuffer.allocate(100000); 22 | channelBuffer.readBytes(byteBuffer); 23 | super.messageReceived(ctx, e); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/monitor/ConnectionMonitor.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.monitor; 2 | 3 | import com.dianping.mocksocks.transport.Connection; 4 | import org.jboss.netty.channel.Channel; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | /** 12 | * @author yihua.huang@dianping.com 13 | */ 14 | public class ConnectionMonitor { 15 | 16 | private static final ConnectionMonitor INSTANCE = new ConnectionMonitor(); 17 | 18 | public static ConnectionMonitor getInstance() { 19 | return INSTANCE; 20 | } 21 | 22 | private ConnectionMonitor(){ 23 | } 24 | 25 | private final Map connectionStatuses = new ConcurrentHashMap(); 26 | 27 | static { 28 | // new Thread(new Runnable() { 29 | // @Override 30 | // public void run() { 31 | // while (true) { 32 | // try { 33 | // Thread.sleep(5000); 34 | // } catch (InterruptedException e) { 35 | // e.printStackTrace(); 36 | // } 37 | // output(); 38 | // } 39 | // } 40 | // }).start(); 41 | } 42 | 43 | public Connection getStatus(Channel channel) { 44 | Connection connection = connectionStatuses.get(channel); 45 | return connection; 46 | } 47 | 48 | public void putStatus(Channel channel,Connection connection) { 49 | connectionStatuses.put(channel, connection); 50 | } 51 | 52 | public List status() { 53 | return new ArrayList(connectionStatuses.values()); 54 | } 55 | 56 | public void clear() { 57 | connectionStatuses.clear(); 58 | } 59 | 60 | @Deprecated 61 | public void output() { 62 | System.out.println("=============================================================================="); 63 | for (Map.Entry connectionStatusEntry : connectionStatuses.entrySet()) { 64 | if (connectionStatusEntry.getValue().getEndTime() != 0l 65 | && connectionStatusEntry.getValue().getEndTime() > (System.currentTimeMillis() - 30000)) { 66 | System.out.println(connectionStatusEntry.getValue()); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/monitor/StatusFormatter.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.monitor; 2 | 3 | import java.text.DecimalFormat; 4 | import java.text.NumberFormat; 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | import java.util.Locale; 8 | 9 | /** 10 | * @author yihua.huang@dianping.com 11 | */ 12 | public class StatusFormatter { 13 | 14 | public static final int MILLS_IN_SECOND = 1000; 15 | public static final int MILLS_IN_MINUTE = MILLS_IN_SECOND * 60; 16 | public static final int MILLS_IN_HOUR = MILLS_IN_MINUTE * 60; 17 | 18 | public static String formatBytes(int bytes) { 19 | NumberFormat numberFormat = DecimalFormat.getInstance(Locale.CHINA); 20 | numberFormat.setMaximumFractionDigits(2); 21 | if (bytes < (1 << 10)) { 22 | return String.valueOf(bytes); 23 | } else if (bytes < (1 << 20)) { 24 | return numberFormat.format(bytes * 1.0 / (1 << 10)) + "K"; 25 | } else if (bytes < (1 << 30)) { 26 | return numberFormat.format(bytes * 1.0 / (1 << 20)) + "M"; 27 | } else { 28 | return numberFormat.format(bytes * 1.0 / (1 << 30)) + "G"; 29 | } 30 | } 31 | 32 | public static String formatTimeStamp(long time) { 33 | SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss/SSS"); 34 | return dateFormat.format(new Date(time)); 35 | } 36 | 37 | public static String formatTimePeriod(long time) { 38 | NumberFormat numberFormat = DecimalFormat.getInstance(Locale.CHINA); 39 | numberFormat.setMaximumFractionDigits(2); 40 | if (time < MILLS_IN_SECOND) { 41 | return String.valueOf(time) + "ms"; 42 | } else if (time < MILLS_IN_MINUTE) { 43 | return numberFormat.format(time * 1.0 / (MILLS_IN_SECOND)) + "s"; 44 | } else if (time < (MILLS_IN_HOUR)) { 45 | return numberFormat.format(time * 1.0 / (MILLS_IN_MINUTE)) + "m"; 46 | } else { 47 | return numberFormat.format(time * 1.0 / (MILLS_IN_HOUR)) + "h"; 48 | } 49 | } 50 | 51 | public static void main(String[] args) { 52 | System.out.println(formatBytes(111111)); 53 | System.out.println(formatBytes(1111111)); 54 | System.out.println(formatBytes(1111111111)); 55 | System.out.println(formatTimeStamp(System.currentTimeMillis())); 56 | System.out.println(formatTimePeriod(111)); 57 | System.out.println(formatTimePeriod(11111)); 58 | System.out.println(formatTimePeriod(11111111)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/monitor/config/Configs.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.monitor.config; 2 | 3 | /** 4 | * @author yihua.huang@dianping.com 5 | */ 6 | public class Configs { 7 | 8 | private final static Configs INSTANCE = new Configs(); 9 | 10 | private boolean record = true; 11 | 12 | public static Configs getInstance() { 13 | return INSTANCE; 14 | } 15 | 16 | public boolean isRecord() { 17 | return record; 18 | } 19 | 20 | public boolean switchRecord() { 21 | this.record = !this.record; 22 | return record; 23 | } 24 | 25 | public void setRecord(boolean record) { 26 | this.record = record; 27 | } 28 | 29 | public String filePath() { 30 | return "/data/appdatas/mocksocks/"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/monitor/config/RulesDao.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.monitor.config; 2 | 3 | import com.dianping.mocksocks.transport.dao.BaseDao; 4 | import org.apache.commons.dbutils.QueryRunner; 5 | import org.apache.commons.dbutils.handlers.MapHandler; 6 | 7 | import java.sql.SQLException; 8 | import java.util.Map; 9 | 10 | /** 11 | * @author yihua.huang@dianping.com 12 | */ 13 | public class RulesDao extends BaseDao { 14 | 15 | public static final String TYPE_REDIRECT = "redirect"; 16 | 17 | public RulesDao() { 18 | initDatabase(); 19 | } 20 | 21 | public String getByType(String type) throws SQLException { 22 | QueryRunner queryRunner = new QueryRunner(getJdbcDataSource()); 23 | Map query = queryRunner.query("select content from Rules where type = ? ", new MapHandler(), 24 | type); 25 | if (query == null || query.get("content") == null) { 26 | return ""; 27 | } 28 | return (String) query.get("content"); 29 | } 30 | 31 | public void setByType(String type, String content) throws SQLException { 32 | QueryRunner queryRunner = new QueryRunner(getJdbcDataSource()); 33 | queryRunner.update("merge into Rules key(type) values (?,?)", type, content); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/protocals/CodecSelector.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.protocals; 2 | 3 | import org.jboss.netty.channel.ChannelDownstreamHandler; 4 | import org.jboss.netty.channel.ChannelUpstreamHandler; 5 | import org.jboss.netty.handler.codec.string.StringDecoder; 6 | import org.jboss.netty.handler.codec.string.StringEncoder; 7 | 8 | import java.net.InetSocketAddress; 9 | 10 | /** 11 | * @author yihua.huang@dianping.com 12 | */ 13 | public class CodecSelector { 14 | 15 | public static ChannelUpstreamHandler decoder(InetSocketAddress remoteAddress, Object msg) { 16 | if (remoteAddress.getPort() >= 2200 && remoteAddress.getPort() < 2300) { 17 | return new HessianDecoder(); 18 | // return new StringDecoder(); 19 | } 20 | // if (remoteAddress.getPort() == 80) { 21 | // return new StringDecoder(); 22 | // } 23 | return new StringDecoder(); 24 | } 25 | 26 | public static ChannelDownstreamHandler encoder(InetSocketAddress remoteAddress, Object msg) { 27 | if (remoteAddress.getPort() >= 2200 && remoteAddress.getPort() < 2300) { 28 | return new HessianEncoder(); 29 | } 30 | if (remoteAddress.getPort() == 80) { 31 | return new StringEncoder(); 32 | } 33 | return new StringEncoder(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/protocals/HessianDecoder.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.protocals; 2 | 3 | import com.caucho.hessian.io.Hessian2Input; 4 | import org.jboss.netty.buffer.ChannelBuffer; 5 | import org.jboss.netty.buffer.ChannelBufferInputStream; 6 | import org.jboss.netty.channel.Channel; 7 | import org.jboss.netty.channel.ChannelHandlerContext; 8 | import org.jboss.netty.handler.codec.replay.ReplayingDecoder; 9 | import org.jboss.netty.handler.codec.replay.VoidEnum; 10 | 11 | public class HessianDecoder extends ReplayingDecoder { 12 | 13 | @Override 14 | protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) 15 | throws Exception { 16 | ChannelBuffer buffer1 = buffer.readBytes(buffer.readInt()); 17 | Hessian2Input h2in = new Hessian2Input(new ChannelBufferInputStream(buffer1)); 18 | try { 19 | Object o = h2in.readObject(); 20 | return o; 21 | } finally { 22 | h2in.close(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/protocals/HessianEncoder.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.protocals; 2 | 3 | /** 4 | * 5 | */ 6 | 7 | import com.caucho.hessian.io.Hessian2Output; 8 | import com.caucho.hessian.io.SerializerFactory; 9 | import org.jboss.netty.buffer.ChannelBuffer; 10 | import org.jboss.netty.buffer.ChannelBufferOutputStream; 11 | import org.jboss.netty.channel.Channel; 12 | import org.jboss.netty.channel.ChannelHandlerContext; 13 | import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; 14 | 15 | import java.util.logging.Level; 16 | import java.util.logging.Logger; 17 | 18 | import static org.jboss.netty.buffer.ChannelBuffers.dynamicBuffer; 19 | 20 | 21 | /** 22 | *

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�seq messa 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 Typetimeout ser 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 ame messageType 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����@S9htt 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 redirectRules = new ArrayList(); 21 | 22 | public static List parse(String exprs) { 23 | List redirectRules = new ArrayList(); 24 | if (StringUtils.isBlank(exprs)) { 25 | return redirectRules; 26 | } 27 | String[] lines = exprs.split("\n"); 28 | for (String line : lines) { 29 | RedirectRule redirectRule = RedirectRule.parse(line); 30 | redirectRules.add(redirectRule); 31 | } 32 | return redirectRules; 33 | } 34 | 35 | public InetSocketAddress getRedirectAddress(InetSocketAddress rawAddress) { 36 | for (RedirectRule redirectRule : redirectRules) { 37 | if (redirectRule.getHostFilter().preserve(rawAddress)) { 38 | return redirectRule.getInetSocketAddress(); 39 | } 40 | } 41 | return rawAddress; 42 | } 43 | 44 | public void setRedirectRules(List redirectRules) { 45 | this.redirectRules = redirectRules; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/rules/filter/ConnectionStatusHostFilter.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.rules.filter; 2 | 3 | import com.dianping.mocksocks.transport.Connection; 4 | 5 | /** 6 | * @author yihua.huang@dianping.com 7 | */ 8 | public class ConnectionStatusHostFilter implements Filter { 9 | 10 | private HostFilter hostFilter; 11 | 12 | public ConnectionStatusHostFilter(String filterExpr) { 13 | this.hostFilter = new HostFilter(filterExpr); 14 | } 15 | 16 | @Override 17 | public boolean preserve(Connection connection) { 18 | if (connection.getAddress() != null) { 19 | return hostFilter.preserve(connection.getAddress()); 20 | } 21 | return false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/rules/filter/Filter.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.rules.filter; 2 | 3 | /** 4 | * @author yihua.huang@dianping.com 5 | */ 6 | public interface Filter { 7 | 8 | public boolean preserve(T t); 9 | } 10 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/rules/filter/HostFilter.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.rules.filter; 2 | 3 | import java.net.InetSocketAddress; 4 | import java.util.regex.Pattern; 5 | 6 | /** 7 | * @author yihua.huang@dianping.com 8 | */ 9 | public class HostFilter implements Filter { 10 | 11 | private Pattern hostFilter; 12 | 13 | private int portFilter = -1; 14 | 15 | public HostFilter(String filterValue) { 16 | if (filterValue.contains(":")) { 17 | portFilter = Integer.parseInt(filterValue.substring(filterValue.lastIndexOf(":") + 1)); 18 | hostFilter = compile(filterValue.substring(0, filterValue.lastIndexOf(":"))); 19 | } else { 20 | this.hostFilter = compile(filterValue); 21 | } 22 | } 23 | 24 | private Pattern compile(String str) { 25 | if (str.contains("*")) { 26 | return Pattern.compile(str.replace(".", "\\.").replace("*", ".*")); 27 | } else { 28 | return Pattern.compile(str, Pattern.LITERAL); 29 | } 30 | } 31 | 32 | @Override 33 | public boolean preserve(InetSocketAddress address) { 34 | if (address == null) { 35 | return false; 36 | } 37 | if (portFilter != -1 && portFilter != address.getPort()) { 38 | return false; 39 | } 40 | String hostName = address.getHostName(); 41 | if (hostName != null && hostFilter.matcher(hostName).find()) { 42 | return true; 43 | } 44 | if (hostFilter.matcher(address.getAddress().getHostAddress()).find()) { 45 | return true; 46 | } 47 | return false; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /mocksocks-transport/src/main/java/com/dianping/mocksocks/transport/utils/AddressUtils.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.utils; 2 | 3 | import java.net.InetAddress; 4 | import java.net.InetSocketAddress; 5 | import java.net.UnknownHostException; 6 | 7 | /** 8 | * @author yihua.huang@dianping.com 9 | */ 10 | public class AddressUtils { 11 | 12 | public static InetSocketAddress parse(String hostAndPort) throws UnknownHostException { 13 | String[] strings = hostAndPort.split(":"); 14 | return new InetSocketAddress(InetAddress.getByName(strings[0]),Integer.parseInt(strings[1])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mocksocks-transport/src/test/java/com/dianping/mocksocks/transport/dao/BaseDapTest.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.dao; 2 | 3 | import org.apache.commons.dbutils.QueryRunner; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.sql.SQLException; 8 | 9 | /** 10 | * @author yihua.huang@dianping.com 11 | */ 12 | public class BaseDapTest { 13 | 14 | @Ignore 15 | @Test 16 | public void testDatasource() throws SQLException { 17 | BaseDao baseDao = new BaseDao(); 18 | baseDao.initDatabase(); 19 | QueryRunner queryRunner = new QueryRunner(baseDao.getJdbcDataSource()); 20 | queryRunner.update("CREATE TABLE TEST(ID INT PRIMARY KEY,\n" + 21 | " NAME VARCHAR(255));"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mocksocks-transport/src/test/java/com/dianping/mocksocks/transport/dao/RulesDaoTest.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.transport.dao; 2 | 3 | import com.dianping.mocksocks.transport.monitor.config.RulesDao; 4 | import org.junit.Test; 5 | 6 | import java.sql.SQLException; 7 | 8 | /** 9 | * @author yihua.huang@dianping.com 10 | */ 11 | public class RulesDaoTest { 12 | 13 | @Test 14 | public void test() throws SQLException { 15 | RulesDao rulesDao = new RulesDao(); 16 | rulesDao.setByType("数据","测试"); 17 | String 数据 = rulesDao.getByType("数据"); 18 | System.out.println(数据); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /mocksocks-web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | mocksocks 7 | com.dianping 8 | 0.0.2-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | com.dianping 13 | mocksocks-web 14 | 0.0.2-SNAPSHOT 15 | 16 | 17 | 18 | us.codecraft 19 | express.java 20 | 0.1.0 21 | 22 | 23 | com.dianping 24 | mocksocks-transport 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.apache.maven.plugins 33 | maven-dependency-plugin 34 | 35 | 36 | copy-dependencies 37 | package 38 | 39 | copy-dependencies 40 | 41 | 42 | ${project.build.directory}/lib 43 | false 44 | false 45 | true 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.apache.maven.plugins 54 | maven-jar-plugin 55 | 56 | 57 | 58 | true 59 | lib/ 60 | com.dianping.mocksocks.web.Bootstrap 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /mocksocks-web/src/main/java/com/dianping/mocksocks/web/Bootstrap.java: -------------------------------------------------------------------------------- 1 | package com.dianping.mocksocks.web; 2 | 3 | import com.dianping.mocksocks.transport.monitor.ConnectionMonitor; 4 | import com.dianping.mocksocks.transport.proxy.SocksProxy; 5 | import us.codecraft.express.WebServer; 6 | import us.codecraft.express.controller.AjaxController; 7 | import us.codecraft.express.controller.ParamMap; 8 | 9 | /** 10 | * @author code4crafter@gmail.com 11 | */ 12 | public class Bootstrap { 13 | 14 | final SocksProxy socksProxy = new SocksProxy(); 15 | 16 | public static void main(String[] args) throws Exception { 17 | Bootstrap bootstrap = new Bootstrap(); 18 | bootstrap.startProxy(); 19 | bootstrap.startServer(); 20 | } 21 | 22 | private boolean startProxy() { 23 | try { 24 | socksProxy.start(); 25 | return true; 26 | } catch (Exception e) { 27 | return false; 28 | } 29 | } 30 | 31 | private void startServer() throws Exception { 32 | WebServer.jettyServer().get("/connectionList", new AjaxController() { 33 | @Override 34 | public Object ajax(ParamMap params) { 35 | getResponse().addHeader("Access-Control-Allow-Origin","*"); 36 | return ConnectionMonitor.getInstance().status(); 37 | } 38 | }).port(8000).start(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.dianping 8 | mocksocks 9 | pom 10 | 0.0.2-SNAPSHOT 11 | monkey-socks 12 | https://github.com/code4craft/monkeysocks 13 | 14 | 15 | 16 | yihua.huang 17 | yihua.huang@dianping.com 18 | 19 | 20 | 21 | mocksocks-transport 22 | mocksocks-junit 23 | mocksocks-gui 24 | mocksocks-client 25 | mocksocks-sample 26 | mocksocks-web 27 | 28 | 29 | 30 | 31 | 32 | org.apache.maven.plugins 33 | maven-compiler-plugin 34 | 3.1 35 | 36 | 1.6 37 | 1.6 38 | utf-8 39 | 40 | 41 | 42 | 43 | 44 | --------------------------------------------------------------------------------