├── .gitignore ├── .vscode └── launch.json ├── README.md ├── application ├── client.go ├── clientFec.go ├── server.go └── serverFec.go ├── codec ├── fPacket.go ├── fecCodec.go ├── interlace.go └── stageBuffer.go ├── connection ├── client.go ├── connPacket.go ├── keepalive.go └── server.go ├── datastructure ├── dataBuffer.go ├── fsm.go └── linkedBlockingQueue.go ├── device └── interface.go ├── fec.json ├── go.mod ├── go.sum ├── jw_test.go ├── main.go ├── misc └── misc.go ├── netconfig ├── profile001.png └── profile002.png /.gitignore: -------------------------------------------------------------------------------- 1 | junkwire 2 | *.log 3 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch test package", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "test", 12 | "program": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JunkWire 2 | 3 | 功能:提高烂网的可用性。 4 | 5 | UDP伪装TCP:伪装为TCP之后减少QoS 6 | 7 | 可配置多服务器,自动断线重连换服,上层无感知:心跳检测,每秒发送5个心跳包。如果5个心跳包都丢失的话就切换到下一个服务器。2秒即可完成。 8 | 9 | 可选FEC前向纠错:20个原始包加10个纠错包,就能将丢包率降低到万分之一。 10 | 11 | 交织编码:可以将短时间集中的丢包均匀开,防止原始包和纠错包都丢掉。 12 | 13 | 配置方法 14 | 15 | junkwire使用tun设备进行数据传送,所以先确定运行环境支持tun设备。运行后会创建一个tun设备叫faketcp,这个设备ip地址可以通过配置文件配置。一般写成10.1.1.1即可,只要不跟自己本地网络环境冲突就行。运行后会虚拟一个网络设备10.1.1.2。 16 | 17 | 服务端配置 18 | 19 | 首先配置服务端DNAT,把对应端口的包转给junkwire处理。 20 | 21 | 首先开启ipv4转发,在 /etc/sysctl.conf 文件中添加 net.ipv4.ip_forward=1 然后运行sysctl -p使其生效。 22 | 23 | 添加iptables规则 iptables -t nat -A PREROUTING -i 网卡名 -d 网卡IP -p tcp --dport 17021(客户端连的端口) -j DNAT --to-destination 10.1.1.2:17021 24 | 25 | wireguard配置举例,根据实际情况改动 26 | 27 | ``` 28 | [Interface] 29 | Address = 10.200.201.1/24 30 | ListenPort = 21007 31 | #ListenPort = 12273 32 | PrivateKey = xxx 33 | MTU = 1340 34 | 35 | [Peer] 36 | PublicKey = xxx 37 | AllowedIPs = 10.200.201.2/32 38 | PersistentKeepalive = 25 39 | ``` 40 | 41 | 服务端junkwire配置文件举例 42 | 43 | ``` 44 | { 45 | "mode": "server", 46 | "queue":500, 47 | "server": { 48 | "tun": { 49 | "deviceIP": "10.1.1.1", 50 | "port": "17021", 51 | "srcIP": "10.1.1.2" 52 | }, 53 | "socket": { 54 | "dstIP": "127.0.0.1", 55 | "dstPort": "21007" 56 | } 57 | }, 58 | "fec": { 59 | "enable":false, //是否启用fec 60 | "seg": 20, //几个数据包 61 | "parity": 20, //几个纠错包 62 | "duration":0, //交织编码的时长 63 | "stageTimeout":8, //桶没装满的话最长等多久 64 | "cap":500, 65 | "row":1000 66 | } 67 | } 68 | ``` 69 | 70 | 启动junkwire ./junkwire -c 配置文件 71 | 72 | 启动wireguard wg-quick up wg0 73 | 74 | 75 | 客户端配置 76 | 77 | 客户端需要让虚拟设备10.1.1.2的数据顺利发送,需要snat 78 | 79 | iptables -t nat -A POSTROUTING -s 10.1.1.2 -p tcp -o eth0 -j SNAT --to-source 本机网卡ip 80 | 81 | 路由配置,防止出口ip也被带进了wireguard 82 | 83 | ip route add 服务端ip/32 via 本地网关 dev eth0 84 | 85 | wireguard配置 86 | 87 | ``` 88 | [Interface] 89 | Address = 10.200.201.2/24 90 | PrivateKey = yJAu/oI+Oo/Mhswqbm3I/3PWYi+WSxX7JpTQ8IoQqWU= 91 | MTU = 1340 92 | 93 | [Peer] 94 | PublicKey = 5/SgVv3hc3f5Fa/XoLo4isBzyrwwATs5sfQv7oWhiTM= 95 | Endpoint = 127.0.0.1:21007 96 | AllowedIPs = 0.0.0.0/1,128.0.0.0/1 97 | PersistentKeepalive = 25 98 | ``` 99 | 100 | junkwire配置举例 101 | 102 | ``` 103 | { 104 | "mode": "client", 105 | "queue":500, 106 | "client": { 107 | "tun": { 108 | "deviceIP": "10.1.1.1", 109 | "port": "8978", 110 | "srcIP": "10.1.1.2", 111 | "peers": [ 112 | { 113 | "ip":"线路1", 114 | "port":"50018" 115 | }, 116 | { 117 | "ip":"线路2", 118 | "port":"17021" 119 | }, 120 | { 121 | "ip":"线路3", 122 | "port":"17021" 123 | } 124 | ] 125 | }, 126 | "socket": { 127 | "listenPort": "21007" 128 | } 129 | }, 130 | "fec": { 131 | "enable":false, 132 | "seg": 20, 133 | "parity": 10, 134 | "stageTimeout": 8, 135 | "duration": 0, 136 | "cap": 500, 137 | "row": 1000 138 | } 139 | } 140 | ``` 141 | 142 | 启动junkwire ./junkwire -c 配置文件 143 | 144 | 启动wireguard wg-quick up wg0 145 | -------------------------------------------------------------------------------- /application/client.go: -------------------------------------------------------------------------------- 1 | package application 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/sodapanda/junkwire/connection" 7 | "github.com/sodapanda/junkwire/misc" 8 | ) 9 | 10 | //AppClient client 11 | type AppClient struct { 12 | conn *net.UDPConn 13 | connAddr *net.UDPAddr 14 | clientConn *connection.ClientConn 15 | rcv int 16 | } 17 | 18 | //NewAppClient new client 19 | func NewAppClient(listenPort string) *AppClient { 20 | ac := new(AppClient) 21 | addr, err := net.ResolveUDPAddr("udp4", ":"+listenPort) 22 | misc.CheckErr(err) 23 | conn, err := net.ListenUDP("udp4", addr) 24 | misc.CheckErr(err) 25 | ac.conn = conn 26 | return ac 27 | } 28 | 29 | //Start start 30 | func (ac *AppClient) Start() { 31 | go ac.socketToDevice() 32 | } 33 | 34 | //SetClientConn set conn 35 | func (ac *AppClient) SetClientConn(clientConn *connection.ClientConn) { 36 | ac.clientConn = clientConn 37 | if clientConn != nil { 38 | ac.clientConn.AddHandler(clientHandler{ac: ac}) 39 | } 40 | } 41 | 42 | func (ac *AppClient) socketToDevice() { 43 | buffer := make([]byte, 2000) 44 | for { 45 | length, addr, err := ac.conn.ReadFromUDP(buffer) 46 | misc.CheckErr(err) 47 | ac.connAddr = addr 48 | data := buffer[:length] 49 | if ac.clientConn != nil { 50 | ac.clientConn.Write(data, false) 51 | } 52 | } 53 | } 54 | 55 | type clientHandler struct { 56 | ac *AppClient 57 | } 58 | 59 | func (ch clientHandler) OnData(data []byte) { 60 | ch.ac.rcv++ 61 | _, err := ch.ac.conn.WriteToUDP(data, ch.ac.connAddr) 62 | if err != nil { 63 | misc.PLog(err.Error()) 64 | } 65 | } 66 | func (ch clientHandler) OnDisconnect(cc *connection.ClientConn) {} 67 | func (ch clientHandler) OnConnect(cc *connection.ClientConn) {} 68 | 69 | //IClient client 70 | type IClient interface { 71 | Start() 72 | SetClientConn(clientConn *connection.ClientConn) 73 | } 74 | -------------------------------------------------------------------------------- /application/clientFec.go: -------------------------------------------------------------------------------- 1 | package application 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "time" 7 | 8 | "github.com/sodapanda/junkwire/codec" 9 | "github.com/sodapanda/junkwire/connection" 10 | "github.com/sodapanda/junkwire/datastructure" 11 | "github.com/sodapanda/junkwire/misc" 12 | ) 13 | 14 | //AppClientFec client with fec 15 | type AppClientFec struct { 16 | conn *net.UDPConn 17 | connAddr *net.UDPAddr 18 | clientConn *connection.ClientConn 19 | rcv int 20 | seg int //数据组个数 21 | parity int //纠错组个数 22 | duration int //交织时间段 毫秒 23 | stageTm int //stagebuffer的超时时间 24 | codec *codec.FecCodec 25 | encodePool *datastructure.DataBufferPool 26 | decodeResult []*datastructure.DataBuffer 27 | il *codec.Interlace //交织 28 | } 29 | 30 | //NewAppClientFec new 31 | func NewAppClientFec(listenPort string, seg int, parity int, icodec *codec.FecCodec, duration int, rowCount int, stm int) *AppClientFec { 32 | ac := new(AppClientFec) 33 | addr, err := net.ResolveUDPAddr("udp4", ":"+listenPort) 34 | misc.CheckErr(err) 35 | conn, err := net.ListenUDP("udp4", addr) 36 | misc.CheckErr(err) 37 | ac.conn = conn 38 | ac.seg = seg 39 | ac.parity = parity 40 | ac.duration = duration 41 | ac.codec = icodec 42 | ac.stageTm = stm 43 | ac.encodePool = datastructure.NewDataBufferPool() 44 | ac.decodeResult = make([]*datastructure.DataBuffer, seg) 45 | for i := range ac.decodeResult { 46 | ac.decodeResult[i] = new(datastructure.DataBuffer) 47 | ac.decodeResult[i].Data = make([]byte, 2000) 48 | } 49 | 50 | if duration > 0 { 51 | inv := time.Duration((float32(duration) / float32(seg+parity)) * 1000) 52 | misc.PLog(fmt.Sprintf("interval %d", inv)) 53 | 54 | ac.il = codec.NewInterlace(rowCount, inv*time.Microsecond, func(dbf *datastructure.DataBuffer) { 55 | if ac.clientConn != nil && ac.clientConn.GetState() == "estb" { 56 | ac.clientConn.Write(dbf.Data[:dbf.Length], false) 57 | } 58 | ac.encodePool.PoolPut(dbf) 59 | }) 60 | } 61 | 62 | return ac 63 | } 64 | 65 | //Start start 66 | func (ac *AppClientFec) Start() { 67 | go ac.socketToDevice() 68 | if ac.duration > 0 { 69 | go ac.il.PushDown() 70 | } 71 | } 72 | 73 | func (ac *AppClientFec) socketToDevice() { 74 | buffer := make([]byte, 2000) 75 | fullDataBuffer := make([]byte, 2000*ac.seg) 76 | sb := codec.NewStageBuffer(ac.codec, ac.seg, fullDataBuffer, time.Duration(ac.stageTm)*time.Millisecond, func(sb *codec.StageBuffer, resultData []byte, realLength int) { 77 | encodeResult := make([]*datastructure.DataBuffer, ac.seg+ac.parity) 78 | for i := range encodeResult { 79 | encodeResult[i] = ac.encodePool.PoolGet() 80 | } 81 | 82 | ac.codec.Encode(resultData, realLength, encodeResult) 83 | if ac.duration > 0 { 84 | ac.il.Put(encodeResult) 85 | } else { 86 | for i := range encodeResult { 87 | item := encodeResult[i] 88 | if ac.clientConn != nil && ac.clientConn.GetState() == "estb" { 89 | ac.clientConn.Write(item.Data[:item.Length], false) 90 | } 91 | ac.encodePool.PoolPut(item) 92 | } 93 | } 94 | }) 95 | 96 | for { 97 | length, addr, err := ac.conn.ReadFromUDP(buffer) 98 | misc.CheckErr(err) 99 | ac.connAddr = addr 100 | data := buffer[:length] 101 | 102 | if ac.clientConn != nil && ac.clientConn.GetState() == "estb" { 103 | sb.Append(data, uint16(length)) 104 | } 105 | } 106 | } 107 | 108 | //SetClientConn set client connection 109 | func (ac *AppClientFec) SetClientConn(clientConn *connection.ClientConn) { 110 | ac.clientConn = clientConn 111 | if clientConn != nil { 112 | ac.clientConn.AddHandler(clientFecHandler{ac: ac}) 113 | } 114 | } 115 | 116 | type clientFecHandler struct { 117 | ac *AppClientFec 118 | } 119 | 120 | func (ch clientFecHandler) OnData(data []byte) { 121 | ch.ac.rcv++ 122 | 123 | rcvPkt := new(codec.FtPacket) 124 | rcvPkt.Decode(data) 125 | 126 | done := ch.ac.codec.Decode(rcvPkt, ch.ac.decodeResult) 127 | if !done { 128 | return 129 | } 130 | 131 | for _, d := range ch.ac.decodeResult { 132 | if d.Length == 0 { 133 | continue 134 | } 135 | _, err := ch.ac.conn.WriteToUDP(d.Data[:d.Length], ch.ac.connAddr) 136 | d.Length = 0 //设置为0 表示没有内容 137 | misc.CheckErr(err) 138 | } 139 | } 140 | func (ch clientFecHandler) OnDisconnect(cc *connection.ClientConn) {} 141 | func (ch clientFecHandler) OnConnect(cc *connection.ClientConn) {} 142 | -------------------------------------------------------------------------------- /application/server.go: -------------------------------------------------------------------------------- 1 | package application 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | 7 | "github.com/sodapanda/junkwire/connection" 8 | "github.com/sodapanda/junkwire/misc" 9 | ) 10 | 11 | //AppServer server 12 | type AppServer struct { 13 | conn *net.UDPConn 14 | serverConn *connection.ServerConn 15 | } 16 | 17 | //NewAppServer new server 18 | func NewAppServer(dstIP string, dstPort string, serverConn *connection.ServerConn) *AppServer { 19 | as := new(AppServer) 20 | address, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", dstIP, dstPort)) 21 | misc.CheckErr(err) 22 | conn, err := net.DialUDP("udp4", nil, address) 23 | misc.CheckErr(err) 24 | as.conn = conn 25 | as.serverConn = serverConn 26 | return as 27 | } 28 | 29 | //Start start 30 | func (as *AppServer) Start() { 31 | go as.socketToDevice() 32 | as.serverConn.AddHandler(handler{ser: as}) 33 | } 34 | 35 | func (as *AppServer) socketToDevice() { 36 | readBuf := make([]byte, 2000) 37 | 38 | for { 39 | length, err := as.conn.Read(readBuf) 40 | misc.CheckErr(err) 41 | data := readBuf[:length] 42 | as.serverConn.Write(data, false) 43 | } 44 | } 45 | 46 | type handler struct { 47 | ser *AppServer 48 | } 49 | 50 | func (h handler) OnData(data []byte, conn *connection.ServerConn) { 51 | _, err := h.ser.conn.Write(data) 52 | if err != nil { 53 | misc.PLog(err.Error()) 54 | } 55 | } 56 | 57 | func (h handler) OnDisconnect() { 58 | 59 | } 60 | 61 | //IServer server interface 62 | type IServer interface { 63 | Start() 64 | } 65 | -------------------------------------------------------------------------------- /application/serverFec.go: -------------------------------------------------------------------------------- 1 | package application 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "time" 7 | 8 | "github.com/sodapanda/junkwire/codec" 9 | "github.com/sodapanda/junkwire/connection" 10 | "github.com/sodapanda/junkwire/datastructure" 11 | "github.com/sodapanda/junkwire/misc" 12 | ) 13 | 14 | //AppServerFec AppServerFec 15 | type AppServerFec struct { 16 | conn *net.UDPConn 17 | serverConn *connection.ServerConn 18 | seg int 19 | parity int 20 | duration int //交织时间段 21 | stageTm int //stagebuffer的超时时间 22 | codec *codec.FecCodec 23 | encodePool *datastructure.DataBufferPool 24 | decodeResult []*datastructure.DataBuffer 25 | il *codec.Interlace //交织 26 | } 27 | 28 | //NewAppServerFec NewAppServerFec 29 | func NewAppServerFec(dstIP string, dstPort string, serverConn *connection.ServerConn, seg int, parity int, icodec *codec.FecCodec, duration int, rowCount int, stm int) *AppServerFec { 30 | as := new(AppServerFec) 31 | address, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", dstIP, dstPort)) 32 | misc.CheckErr(err) 33 | conn, err := net.DialUDP("udp4", nil, address) 34 | misc.CheckErr(err) 35 | as.conn = conn 36 | as.serverConn = serverConn 37 | as.seg = seg 38 | as.parity = parity 39 | as.duration = duration 40 | as.stageTm = stm 41 | as.encodePool = datastructure.NewDataBufferPool() 42 | as.decodeResult = make([]*datastructure.DataBuffer, seg) 43 | as.codec = icodec 44 | for i := range as.decodeResult { 45 | as.decodeResult[i] = new(datastructure.DataBuffer) 46 | as.decodeResult[i].Data = make([]byte, 2000) 47 | } 48 | 49 | if duration > 0 { 50 | inv := time.Duration((float32(duration) / float32(seg+parity)) * 1000) 51 | misc.PLog(fmt.Sprintf("interval %d", inv)) 52 | 53 | as.il = codec.NewInterlace(rowCount, inv*time.Microsecond, func(dbf *datastructure.DataBuffer) { 54 | if as.serverConn != nil { 55 | as.serverConn.Write(dbf.Data[:dbf.Length], false) 56 | } 57 | as.encodePool.PoolPut(dbf) 58 | }) 59 | 60 | } 61 | return as 62 | } 63 | 64 | //Start start 65 | func (as *AppServerFec) Start() { 66 | go as.socketToDevice() 67 | if as.duration > 0 { 68 | go as.il.PushDown() 69 | } 70 | as.serverConn.AddHandler(handlerFec{ser: as}) 71 | } 72 | 73 | func (as *AppServerFec) socketToDevice() { 74 | readBuf := make([]byte, 2000) 75 | fullDataBuffer := make([]byte, 2000*as.seg) 76 | sb := codec.NewStageBuffer(as.codec, as.seg, fullDataBuffer, time.Duration(as.stageTm)*time.Millisecond, func(sb *codec.StageBuffer, resultData []byte, realLength int) { 77 | encodeResult := make([]*datastructure.DataBuffer, as.seg+as.parity) 78 | for i := range encodeResult { 79 | encodeResult[i] = as.encodePool.PoolGet() 80 | } 81 | 82 | as.codec.Encode(resultData, realLength, encodeResult) 83 | 84 | if as.duration > 0 { 85 | as.il.Put(encodeResult) 86 | } else { 87 | for i := range encodeResult { 88 | item := encodeResult[i] 89 | as.serverConn.Write(item.Data[:item.Length], false) 90 | as.encodePool.PoolPut(item) 91 | } 92 | } 93 | }) 94 | 95 | for { 96 | length, err := as.conn.Read(readBuf) 97 | misc.CheckErr(err) 98 | data := readBuf[:length] 99 | sb.Append(data, uint16(length)) 100 | } 101 | } 102 | 103 | type handlerFec struct { 104 | ser *AppServerFec 105 | } 106 | 107 | func (h handlerFec) OnData(data []byte, conn *connection.ServerConn) { 108 | rcvPkt := new(codec.FtPacket) 109 | rcvPkt.Decode(data) 110 | 111 | done := h.ser.codec.Decode(rcvPkt, h.ser.decodeResult) 112 | if !done { 113 | return 114 | } 115 | 116 | for _, d := range h.ser.decodeResult { 117 | if d.Length == 0 { 118 | continue 119 | } 120 | _, err := h.ser.conn.Write(d.Data[:d.Length]) 121 | d.Length = 0 //设置为0 表示没有内容 122 | misc.CheckErr(err) 123 | } 124 | } 125 | 126 | func (h handlerFec) OnDisconnect() { 127 | 128 | } 129 | -------------------------------------------------------------------------------- /codec/fPacket.go: -------------------------------------------------------------------------------- 1 | package codec 2 | 3 | import ( 4 | "encoding/binary" 5 | "sync" 6 | ) 7 | 8 | //FtPacket protocol 9 | type FtPacket struct { 10 | gID uint64 //整个fec组的id 11 | index uint16 //该包在组中的位置 12 | realLength uint16 //去掉补齐部分的真实长度 13 | data []byte 14 | len int //在pool里的时候记录长度用 15 | } 16 | 17 | //Encode encode 18 | func (ftp *FtPacket) Encode(result []byte) int { 19 | binary.BigEndian.PutUint64(result, ftp.gID) 20 | binary.BigEndian.PutUint16(result[8:], ftp.index) 21 | binary.BigEndian.PutUint16(result[10:], ftp.realLength) 22 | copy(result[12:], ftp.data) 23 | return 12 + len(ftp.data) 24 | } 25 | 26 | //Decode decode 27 | func (ftp *FtPacket) Decode(data []byte) { 28 | ftp.gID = binary.BigEndian.Uint64(data[0:]) 29 | ftp.index = binary.BigEndian.Uint16(data[8:]) 30 | ftp.realLength = binary.BigEndian.Uint16(data[10:]) 31 | ftp.data = data[12:] 32 | } 33 | 34 | ////// 35 | 36 | var mFtPool = newFtPool() 37 | 38 | type ftPool struct { 39 | dataPool sync.Pool 40 | } 41 | 42 | func newFtPool() *ftPool { 43 | ftpool := new(ftPool) 44 | ftpool.dataPool = sync.Pool{ 45 | New: func() interface{} { 46 | data := new(FtPacket) 47 | data.data = make([]byte, 2000) 48 | return data 49 | }, 50 | } 51 | return ftpool 52 | } 53 | 54 | func (p *ftPool) poolGet() *FtPacket { 55 | item := p.dataPool.Get() 56 | return item.(*FtPacket) 57 | } 58 | 59 | func (p *ftPool) poolPut(item *FtPacket) { 60 | p.dataPool.Put(item) 61 | } 62 | -------------------------------------------------------------------------------- /codec/fecCodec.go: -------------------------------------------------------------------------------- 1 | package codec 2 | 3 | import ( 4 | "container/list" 5 | "encoding/binary" 6 | "fmt" 7 | "math" 8 | "strings" 9 | 10 | "github.com/klauspost/reedsolomon" 11 | "github.com/sodapanda/junkwire/datastructure" 12 | "github.com/sodapanda/junkwire/misc" 13 | ) 14 | 15 | //FecCodec fec 16 | type FecCodec struct { 17 | segCount int 18 | fecSegCount int 19 | encodeWorkspace [][]byte 20 | decodeLinkMap map[uint64][]*FtPacket 21 | keyList *list.List 22 | decodeMapCapacity int 23 | decodeTempWorkspace [][]byte 24 | encoder reedsolomon.Encoder 25 | tmpPool [][]byte //因为每次fec桶大小不一样 26 | currentID uint64 27 | fullPacketHolder []byte //分包合并然后拆分用的内存空间 28 | lenKindMap map[int]int 29 | } 30 | 31 | //NewFecCodec new 32 | func NewFecCodec(segCount int, fecSegCount int, decodeMapCap int) *FecCodec { 33 | codec := new(FecCodec) 34 | codec.segCount = segCount 35 | codec.fecSegCount = fecSegCount 36 | codec.encodeWorkspace = make([][]byte, segCount+fecSegCount) 37 | codec.decodeLinkMap = make(map[uint64][]*FtPacket) 38 | codec.lenKindMap = make(map[int]int) 39 | codec.keyList = list.New() 40 | codec.decodeMapCapacity = decodeMapCap 41 | codec.decodeTempWorkspace = make([][]byte, segCount+fecSegCount) 42 | codec.encoder, _ = reedsolomon.New(segCount, fecSegCount) 43 | codec.tmpPool = make([][]byte, fecSegCount) 44 | for i := range codec.tmpPool { 45 | codec.tmpPool[i] = make([]byte, 2000) 46 | } 47 | 48 | codec.fullPacketHolder = make([]byte, 2000*(segCount+fecSegCount)) 49 | 50 | return codec 51 | } 52 | 53 | //Encode encode 54 | func (codec *FecCodec) Encode(data []byte, realLength int, result []*datastructure.DataBuffer) { 55 | segSize := (len(data)) / codec.segCount 56 | for i := 0; i < codec.segCount; i++ { 57 | start := i * segSize 58 | end := start + segSize 59 | codec.encodeWorkspace[i] = data[start:end] 60 | } 61 | 62 | for i := 0; i < codec.fecSegCount; i++ { 63 | codec.encodeWorkspace[codec.segCount+i] = codec.tmpPool[i][:segSize] 64 | } 65 | 66 | codec.encoder.Encode(codec.encodeWorkspace) 67 | 68 | codec.currentID = codec.currentID + 1 69 | 70 | for i, data := range codec.encodeWorkspace { 71 | ftp := new(FtPacket) 72 | ftp.gID = codec.currentID 73 | ftp.index = uint16(i) 74 | ftp.realLength = uint16(realLength) 75 | ftp.data = data 76 | codeLen := ftp.Encode(result[i].Data) 77 | result[i].Length = codeLen //指示有效长度 78 | } 79 | } 80 | 81 | //Decode decode 82 | func (codec *FecCodec) Decode(ftp *FtPacket, result []*datastructure.DataBuffer) bool { 83 | _, found := codec.decodeLinkMap[ftp.gID] 84 | if !found { 85 | codec.decodeLinkMap[ftp.gID] = make([]*FtPacket, codec.segCount+codec.fecSegCount) 86 | codec.keyList.PushBack(ftp.gID) 87 | } 88 | 89 | if len(codec.decodeLinkMap) > codec.decodeMapCapacity { 90 | firstKeyElm := codec.keyList.Front() 91 | firstKey := firstKeyElm.Value.(uint64) 92 | ftps := codec.decodeLinkMap[firstKey] 93 | for _, ftp := range ftps { 94 | if ftp != nil { 95 | mFtPool.poolPut(ftp) 96 | } 97 | } 98 | delete(codec.decodeLinkMap, firstKey) 99 | codec.keyList.Remove(firstKeyElm) 100 | } 101 | 102 | poolFtp := mFtPool.poolGet() 103 | if poolFtp == nil { 104 | fmt.Println("poolFtp is nil!!") 105 | } 106 | poolFtp.len = len(ftp.data) 107 | poolFtp.gID = ftp.gID 108 | poolFtp.index = ftp.index 109 | poolFtp.realLength = ftp.realLength 110 | copy(poolFtp.data, ftp.data) 111 | 112 | row := codec.decodeLinkMap[ftp.gID] 113 | if row[ftp.index] != nil { 114 | misc.PLog(fmt.Sprintf("Dup!,%d,%d", ftp.gID, ftp.index)) 115 | } 116 | row[ftp.index] = poolFtp 117 | 118 | gotCount := 0 119 | allSegGot := false 120 | for i, v := range row { 121 | if v != nil { 122 | gotCount++ 123 | } 124 | if i == codec.segCount-1 && gotCount == codec.segCount { 125 | allSegGot = true 126 | } 127 | } 128 | 129 | if gotCount != codec.segCount { 130 | return false 131 | } 132 | 133 | for i := range row { 134 | thisFtp := row[i] 135 | if thisFtp != nil { 136 | codec.decodeTempWorkspace[i] = thisFtp.data[:thisFtp.len] 137 | } else { 138 | codec.decodeTempWorkspace[i] = make([]byte, 0, len(ftp.data)) 139 | } 140 | } 141 | 142 | if !allSegGot { 143 | codec.encoder.Reconstruct(codec.decodeTempWorkspace) 144 | 145 | // 146 | ftpDataLen := len(ftp.data) 147 | _, lenKindFound := codec.lenKindMap[ftpDataLen] 148 | if !lenKindFound { 149 | codec.lenKindMap[ftpDataLen] = 1 150 | } else { 151 | codec.lenKindMap[ftpDataLen] = codec.lenKindMap[ftpDataLen] + 1 152 | } 153 | // 154 | } 155 | 156 | fCursor := 0 157 | for i, data := range codec.decodeTempWorkspace { 158 | if i == codec.segCount { 159 | break 160 | } 161 | copy(codec.fullPacketHolder[fCursor:], data) 162 | fCursor = fCursor + len(data) 163 | } 164 | 165 | fullData := codec.fullPacketHolder[:ftp.realLength] 166 | 167 | sCursor := 0 168 | //如果是超时过来的话,只有一个包 169 | for i := 0; i < codec.segCount; i++ { 170 | if sCursor >= len(fullData) { 171 | break 172 | } 173 | length := binary.BigEndian.Uint16(fullData[sCursor:]) 174 | sCursor = sCursor + 2 175 | copy(result[i].Data, fullData[sCursor:sCursor+int(length)]) 176 | sCursor = sCursor + int(length) 177 | result[i].Length = int(length) 178 | } 179 | 180 | return true 181 | } 182 | 183 | //Align align 184 | func (codec *FecCodec) Align(length int) int { 185 | minBucket := math.Ceil(float64(length) / float64(codec.segCount)) 186 | return int(minBucket) * codec.segCount 187 | } 188 | 189 | //Dump dump 190 | func (codec *FecCodec) Dump() string { 191 | var sb strings.Builder 192 | inCompCount := 0 193 | for e := codec.keyList.Front(); e != nil; e = e.Next() { 194 | gotCount := 0 195 | fKey := e.Value.(uint64) 196 | ftPkts := codec.decodeLinkMap[fKey] 197 | fmt.Fprintf(&sb, "%d", fKey) 198 | for _, pkt := range ftPkts { 199 | if pkt == nil { 200 | fmt.Fprintf(&sb, "❌") 201 | } else { 202 | fmt.Fprintf(&sb, "✅") 203 | gotCount++ 204 | } 205 | } 206 | if gotCount < codec.segCount { 207 | inCompCount++ 208 | } 209 | fmt.Fprintf(&sb, "\n") 210 | } 211 | fmt.Fprintf(&sb, "not complete row %d", inCompCount) 212 | return sb.String() 213 | } 214 | 215 | //DumpLenKind lenkind 216 | func (codec *FecCodec) DumpLenKind() string { 217 | var sb strings.Builder 218 | for lenKind, count := range codec.lenKindMap { 219 | fmt.Fprintf(&sb, "%d:%d\n", lenKind, count) 220 | } 221 | fmt.Fprintf(&sb, "total kind:%d\n", len(codec.lenKindMap)) 222 | return sb.String() 223 | } 224 | -------------------------------------------------------------------------------- /codec/interlace.go: -------------------------------------------------------------------------------- 1 | package codec 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | 8 | "github.com/sodapanda/junkwire/datastructure" 9 | ) 10 | 11 | type row struct { 12 | datas []*datastructure.DataBuffer 13 | cursor int //下一个要发的index 14 | runOut bool 15 | } 16 | 17 | //Interlace 交织 18 | type Interlace struct { 19 | table []*row 20 | size int //有数据的行数 21 | cap int //最多几行 22 | callback func(dbf *datastructure.DataBuffer) 23 | lock *sync.Mutex 24 | notFull *sync.Cond 25 | notEmpty *sync.Cond 26 | interval time.Duration //多久发完一组包 27 | stopFlag bool 28 | } 29 | 30 | //NewInterlace new 31 | func NewInterlace(cap int, interval time.Duration, callback func(dbf *datastructure.DataBuffer)) *Interlace { 32 | il := new(Interlace) 33 | il.table = make([]*row, cap) 34 | il.size = 0 35 | il.cap = cap 36 | il.callback = callback 37 | il.lock = new(sync.Mutex) 38 | il.notFull = sync.NewCond(il.lock) 39 | il.notEmpty = sync.NewCond(il.lock) 40 | il.interval = interval 41 | for i := range il.table { 42 | item := new(row) 43 | item.runOut = true 44 | il.table[i] = item 45 | } 46 | return il 47 | } 48 | 49 | //Put put 50 | func (il *Interlace) Put(intpuData []*datastructure.DataBuffer) { 51 | il.lock.Lock() 52 | 53 | for il.size == il.cap { 54 | il.notFull.Wait() 55 | } 56 | 57 | for _, thisRow := range il.table { 58 | if thisRow.runOut { 59 | thisRow.datas = intpuData 60 | thisRow.cursor = 0 61 | thisRow.runOut = false 62 | il.size = il.size + 1 63 | break 64 | } 65 | } 66 | il.lock.Unlock() 67 | il.notEmpty.Signal() 68 | } 69 | 70 | //PushDown push down to device 71 | func (il *Interlace) PushDown() { 72 | for !il.stopFlag { 73 | il.lock.Lock() 74 | for il.size == 0 { 75 | il.notEmpty.Wait() 76 | } 77 | 78 | //把每一行的cursor向前推进(调用回调),到头了就标记到头了 79 | for _, row := range il.table { 80 | if row.runOut { 81 | continue 82 | } 83 | data := row.datas[row.cursor] 84 | il.callback(data) 85 | row.cursor = row.cursor + 1 86 | if row.cursor == len(row.datas) { 87 | row.runOut = true 88 | il.size-- 89 | il.notFull.Signal() 90 | } 91 | } 92 | il.lock.Unlock() 93 | time.Sleep(il.interval) 94 | } 95 | } 96 | 97 | //Dump debug 98 | func (il *Interlace) Dump() { 99 | for i := range il.table { 100 | row := il.table[i] 101 | for _, item := range row.datas { 102 | fmt.Print(item.Tag + " ") 103 | } 104 | fmt.Print("\n") 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /codec/stageBuffer.go: -------------------------------------------------------------------------------- 1 | package codec 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | //StageBuffer buffer 11 | type StageBuffer struct { 12 | buffer []byte 13 | capacity int 14 | size int 15 | cursor int 16 | resultBuffer []byte 17 | waitTime time.Duration 18 | tm *time.Timer 19 | lock *sync.Mutex 20 | callback func(*StageBuffer, []byte, int) 21 | icodec *FecCodec 22 | fullCh chan bool 23 | waitDoneCh chan bool 24 | } 25 | 26 | //NewStageBuffer new 27 | func NewStageBuffer(icodec *FecCodec, cap int, rb []byte, timeout time.Duration, callback func(*StageBuffer, []byte, int)) *StageBuffer { 28 | sbuffer := new(StageBuffer) 29 | sbuffer.capacity = cap 30 | sbuffer.buffer = make([]byte, 2000*cap) 31 | sbuffer.size = 0 32 | sbuffer.cursor = 0 33 | sbuffer.resultBuffer = rb 34 | sbuffer.waitTime = timeout 35 | sbuffer.lock = new(sync.Mutex) 36 | sbuffer.callback = callback 37 | sbuffer.icodec = icodec 38 | sbuffer.fullCh = make(chan bool) 39 | sbuffer.waitDoneCh = make(chan bool) 40 | return sbuffer 41 | } 42 | 43 | var fullCount int 44 | 45 | //Append append 46 | func (sb *StageBuffer) Append(data []byte, length uint16) { 47 | //放入buffer 48 | sb.lock.Lock() 49 | binary.BigEndian.PutUint16(sb.buffer[sb.cursor:], length) 50 | sb.cursor = sb.cursor + 2 51 | copy(sb.buffer[sb.cursor:], data) 52 | sb.cursor = sb.cursor + int(length) 53 | sb.size = sb.size + 1 54 | 55 | if sb.size == 1 { //如果只有1个 开启timer 56 | if sb.tm == nil { 57 | sb.tm = time.NewTimer(sb.waitTime) 58 | } else { 59 | rstFlag := sb.tm.Reset(sb.waitTime) 60 | if rstFlag { 61 | fmt.Println("reset on not stop timer") 62 | } 63 | } 64 | go func() { //todo leak 65 | select { 66 | case <-sb.tm.C: 67 | sb.lock.Lock() 68 | if sb.size == 0 { 69 | //空 不操作 70 | fmt.Println("go2 wake up timer size 0") 71 | sb.waitDoneCh <- true 72 | } 73 | if sb.size > 0 && sb.size < sb.capacity { 74 | //超时没满 发送数据 不用通知 75 | sb.sendOut() 76 | } 77 | 78 | if sb.size == sb.capacity { 79 | //超时 满了:不发送数据 通知 80 | sb.waitDoneCh <- true 81 | } 82 | sb.lock.Unlock() 83 | case <-sb.fullCh: 84 | //没超时 85 | sb.waitDoneCh <- true 86 | } 87 | }() 88 | sb.lock.Unlock() 89 | } else if sb.size == sb.capacity { //如果满了 发出去 90 | sb.sendOut() 91 | sb.lock.Unlock() 92 | expr := !sb.tm.Stop() //true:调用stop的时候还没到期 false:调用stop的时候已经到期了 需要检查chann有没有关闭 93 | if expr { 94 | fmt.Println("full,go2 waiting") 95 | <-sb.waitDoneCh 96 | } else { 97 | sb.fullCh <- true 98 | <-sb.waitDoneCh 99 | } 100 | } else { 101 | sb.lock.Unlock() 102 | } 103 | } 104 | 105 | func (sb *StageBuffer) sendOut() { 106 | alignLen := sb.icodec.Align(sb.cursor) 107 | copy(sb.resultBuffer, sb.buffer[:sb.cursor]) 108 | sb.size = 0 109 | sb.callback(sb, sb.resultBuffer[:alignLen], sb.cursor) 110 | sb.cursor = 0 111 | } 112 | -------------------------------------------------------------------------------- /connection/client.go: -------------------------------------------------------------------------------- 1 | package connection 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "net" 7 | "time" 8 | 9 | "github.com/google/netstack/tcpip" 10 | ds "github.com/sodapanda/junkwire/datastructure" 11 | "github.com/sodapanda/junkwire/device" 12 | "github.com/sodapanda/junkwire/misc" 13 | ) 14 | 15 | //ClientConnHandler handler 16 | type ClientConnHandler interface { 17 | OnData([]byte) 18 | OnDisconnect(cc *ClientConn) 19 | OnConnect(cc *ClientConn) 20 | } 21 | 22 | //ClientConn client connection 23 | type ClientConn struct { 24 | tun *device.TunInterface 25 | srcIP tcpip.Address 26 | dstIP tcpip.Address 27 | srcPort uint16 28 | dstPort uint16 29 | sendID uint16 30 | lastRcvSeq uint32 31 | lastRcvLen uint32 32 | lastRcvAck uint32 33 | payloadsFromUpLayer *ds.BlockingQueue 34 | pool *ds.DataBufferPool 35 | fsm *ds.Fsm 36 | handler ClientConnHandler 37 | tunStopChan chan string 38 | readLoopStopChan chan string 39 | kp *keeper 40 | kpStopChan chan string 41 | } 42 | 43 | //NewClientConn new client connection 44 | func NewClientConn(tun *device.TunInterface, srcIP string, dstIP string, srcPort uint16, dstPort uint16, qLen int) *ClientConn { 45 | cc := new(ClientConn) 46 | cc.pool = ds.NewDataBufferPool() 47 | cc.payloadsFromUpLayer = ds.NewBlockingQueue(qLen) 48 | cc.tun = tun 49 | cc.srcIP = tcpip.Address(net.ParseIP(srcIP).To4()) 50 | cc.dstIP = tcpip.Address(net.ParseIP(dstIP).To4()) 51 | cc.srcPort = srcPort 52 | cc.dstPort = dstPort 53 | cc.tunStopChan = make(chan string, 1) 54 | cc.readLoopStopChan = make(chan string, 1) 55 | cc.kpStopChan = make(chan string, 1) 56 | cc.kp = newKeeper(cc, cc.kpStopChan, func() { 57 | cc.tun.Interrupt() 58 | cc.payloadsFromUpLayer.Interrupt() 59 | cc.handler.OnDisconnect(cc) 60 | }) 61 | 62 | cc.fsm = ds.NewFsm("stop") 63 | 64 | cc.fsm.AddRule("stop", ds.Event{Name: "sdsyn"}, "synsd", func(ev ds.Event) { 65 | cp := ConnPacket{} 66 | cp.syn = true 67 | cp.srcIP = cc.srcIP 68 | cp.dstIP = cc.dstIP 69 | cp.srcPort = cc.srcPort 70 | cp.dstPort = cc.dstPort 71 | cp.ack = false 72 | cp.ackNum = 1100 73 | cp.seqNum = 1000 //client的第一个seq是随机的 74 | cp.payload = nil 75 | cp.rst = false 76 | cp.ipID++ 77 | 78 | misc.PLog(fmt.Sprintf("\nsend syn %s:%d => %s:%d", cp.srcIP.String(), cp.srcPort, cp.dstIP.String(), cp.dstPort)) 79 | 80 | result := make([]byte, 40) 81 | cp.encode(result) 82 | cc.tun.Write(result) 83 | go func() { 84 | time.Sleep(6 * time.Second) 85 | cc.fsm.OnEvent(ds.Event{Name: "synTimeout"}) 86 | }() 87 | }) 88 | 89 | cc.fsm.AddRule("synsd", ds.Event{Name: "synTimeout"}, "stop", func(ev ds.Event) { 90 | misc.PLog("syn sent wait timeout") 91 | 92 | cc.tun.Interrupt() 93 | cc.payloadsFromUpLayer.Interrupt() 94 | cc.kp.stop() 95 | cc.handler.OnDisconnect(cc) 96 | }) 97 | 98 | cc.fsm.AddRule("synsd", ds.Event{Name: "rcvsynack"}, "gotsynsck", func(ev ds.Event) { 99 | misc.PLog("got syn+ack,sending ack") 100 | cp := ConnPacket{} 101 | cp.syn = false 102 | cp.srcIP = cc.srcIP 103 | cp.dstIP = cc.dstIP 104 | cp.srcPort = cc.srcPort 105 | cp.dstPort = cc.dstPort 106 | cp.ack = true 107 | cp.ackNum = cc.lastRcvSeq + cc.lastRcvLen 108 | cp.seqNum = cc.lastRcvAck 109 | cp.payload = nil 110 | cp.rst = false 111 | cp.ipID++ 112 | 113 | result := make([]byte, 40) 114 | cp.encode(result) 115 | cc.tun.Write(result) 116 | cc.fsm.OnEvent(ds.Event{Name: "sdack"}) 117 | }) 118 | 119 | cc.fsm.AddRule("synsd", ds.Event{Name: "rcvrst"}, "error", func(ev ds.Event) { 120 | misc.PLog("synsd rcvrst,error") 121 | cc.reset() 122 | cc.fsm.OnEvent(ds.Event{Name: "sdrst"}) 123 | }) 124 | 125 | cc.fsm.AddRule("gotsynsck", ds.Event{Name: "sdack"}, "estb", func(ev ds.Event) { 126 | misc.PLog("client estb") 127 | cc.handler.OnConnect(cc) 128 | go cc.kp.start() 129 | }) 130 | 131 | cc.fsm.AddRule("estb", ds.Event{Name: "rcvsynack"}, "error", func(ev ds.Event) { 132 | misc.PLog("estb rcvsynack,error") 133 | cc.reset() 134 | cc.fsm.OnEvent(ds.Event{Name: "sdrst"}) 135 | }) 136 | 137 | cc.fsm.AddRule("estb", ds.Event{Name: "rcvack"}, "estb", func(ev ds.Event) { 138 | cp := ev.ConnPacket.(ConnPacket) 139 | if cp.payload != nil && len(cp.payload) > 0 { 140 | cc.handler.OnData(cp.payload) 141 | } 142 | }) 143 | 144 | cc.fsm.AddRule("estb", ds.Event{Name: "rcvrst"}, "error", func(ev ds.Event) { 145 | misc.PLog("estb:recv reset") 146 | cc.reset() 147 | cc.fsm.OnEvent(ds.Event{Name: "sdrst"}) 148 | }) 149 | 150 | cc.fsm.AddRule("error", ds.Event{Name: "sdrst"}, "stop", func(ev ds.Event) { 151 | cc.tun.Interrupt() 152 | cc.payloadsFromUpLayer.Interrupt() 153 | cc.kp.stop() 154 | cc.handler.OnDisconnect(cc) 155 | //todo 清理队列里没消费的 156 | misc.PLog("stop state") 157 | }) 158 | 159 | cc.fsm.OnEvent(ds.Event{Name: "sdsyn"}) 160 | 161 | go cc.readLoop(cc.readLoopStopChan) 162 | go cc.q2Tun(cc.tunStopChan) 163 | return cc 164 | } 165 | 166 | //AddHandler add callback 167 | func (cc *ClientConn) AddHandler(handler ClientConnHandler) { 168 | cc.handler = handler 169 | } 170 | 171 | //WaitStop block wait for stop 172 | func (cc *ClientConn) WaitStop() { 173 | misc.PLog("start wait stop ") 174 | <-cc.readLoopStopChan 175 | <-cc.tunStopChan 176 | <-cc.kpStopChan 177 | misc.PLog("wait stop end") 178 | } 179 | 180 | func (cc *ClientConn) reset() { 181 | misc.PLog("send reset") 182 | cp := ConnPacket{} 183 | cp.syn = false 184 | cp.ack = false 185 | cp.rst = true 186 | cp.srcIP = cc.srcIP 187 | cp.dstIP = cc.dstIP 188 | cp.srcPort = cc.srcPort 189 | cp.dstPort = cc.dstPort 190 | cp.seqNum = cc.lastRcvAck 191 | cp.ackNum = cc.lastRcvSeq + cc.lastRcvLen 192 | cp.payload = nil 193 | result := make([]byte, 40) 194 | cp.encode(result) 195 | cc.tun.Write(result) 196 | cc.sendID = 0 197 | } 198 | 199 | func (cc *ClientConn) readLoop(stopChan chan string) { 200 | for { 201 | dataBuffer := cc.tun.Read() 202 | cp := ConnPacket{} 203 | if dataBuffer == nil || dataBuffer.Length == 0 { 204 | misc.PLog("client conn read loop exit") 205 | break 206 | } 207 | cp.decode(dataBuffer.Data[:dataBuffer.Length]) 208 | if cp.srcIP != cc.dstIP || cp.srcPort != cc.dstPort { 209 | // misc.PLog("read packet not from server.drop") 210 | // misc.PLog(fmt.Sprintf(" %s:%d\n", cp.srcIP.String(), cp.srcPort)) 211 | cc.tun.Recycle(dataBuffer) 212 | continue 213 | } 214 | if cp.window != 6543 { 215 | misc.PLog("read window is not 6543!!Danger Drop") 216 | misc.PLog(fmt.Sprintf(" %s:%d win:%d\n", cp.srcIP.String(), cp.srcPort, cp.window)) 217 | continue 218 | } 219 | cc.lastRcvSeq = cp.seqNum 220 | cc.lastRcvAck = cp.ackNum 221 | cc.lastRcvLen = uint32(len(cp.payload)) 222 | if cp.syn { 223 | cc.lastRcvLen = 1 224 | } 225 | if cp.push { //心跳包处理 226 | content := binary.BigEndian.Uint64(cp.payload) 227 | cc.kp.rcv(content) 228 | cc.tun.Recycle(dataBuffer) 229 | continue 230 | } 231 | et := ds.Event{} 232 | if cp.syn && cp.ack { 233 | et.Name = "rcvsynack" 234 | } else if cp.ack { 235 | et.Name = "rcvack" 236 | } 237 | if cp.rst { 238 | et.Name = "rcvrst" 239 | } 240 | et.ConnPacket = cp 241 | cc.fsm.OnEvent(et) 242 | cc.tun.Recycle(dataBuffer) 243 | } 244 | 245 | stopChan <- "readLoopStop" 246 | } 247 | 248 | func (cc *ClientConn) Write(data []byte, isKp bool) { 249 | dbf := cc.pool.PoolGet() 250 | cp := ConnPacket{} 251 | cp.ipID = cc.sendID 252 | cc.sendID++ 253 | cp.srcIP = cc.srcIP 254 | cp.dstIP = cc.dstIP 255 | cp.srcPort = cc.srcPort 256 | cp.dstPort = cc.dstPort 257 | cp.syn = false 258 | cp.ack = true 259 | cp.rst = false 260 | if isKp { 261 | cp.push = true 262 | } 263 | cp.seqNum = cc.lastRcvAck 264 | cp.ackNum = cc.lastRcvSeq + cc.lastRcvLen 265 | cp.payload = data 266 | length := cp.encode(dbf.Data) 267 | dbf.Length = int(length) 268 | cc.payloadsFromUpLayer.Put(dbf) 269 | } 270 | 271 | func (cc *ClientConn) q2Tun(stopChan chan string) { 272 | for { 273 | dbf := cc.payloadsFromUpLayer.Get() 274 | if dbf == nil { 275 | misc.PLog("q2tun read end") 276 | break 277 | } 278 | data := dbf.Data[:dbf.Length] 279 | cp := ConnPacket{} 280 | cp.decode(data) 281 | if cp.dstIP != cc.dstIP { 282 | misc.PLog("client send not to server.drop") 283 | cc.pool.PoolPut(dbf) 284 | continue 285 | } 286 | cc.tun.Write(data) 287 | cc.pool.PoolPut(dbf) 288 | } 289 | 290 | stopChan <- "queue to tun stop" 291 | } 292 | 293 | //GetState GetState 294 | func (cc *ClientConn) GetState() string { 295 | if cc.fsm != nil { 296 | return cc.fsm.Current 297 | } 298 | return "" 299 | } 300 | -------------------------------------------------------------------------------- /connection/connPacket.go: -------------------------------------------------------------------------------- 1 | package connection 2 | 3 | import ( 4 | "github.com/google/netstack/tcpip" 5 | "github.com/google/netstack/tcpip/header" 6 | "github.com/google/netstack/tcpip/transport/tcp" 7 | ) 8 | 9 | //ConnPacket connectiong packet IP TCP header 10 | type ConnPacket struct { 11 | ipID uint16 12 | srcIP tcpip.Address 13 | dstIP tcpip.Address 14 | srcPort uint16 15 | dstPort uint16 16 | syn bool 17 | ack bool 18 | rst bool 19 | push bool 20 | seqNum uint32 21 | ackNum uint32 22 | window uint16 23 | payload []byte 24 | } 25 | 26 | func (cp *ConnPacket) encode(result []byte) uint16 { 27 | copy(result[40:], cp.payload) 28 | ipPacket := header.IPv4(result[0:]) 29 | //IP header 30 | ipHeader := header.IPv4Fields{} 31 | ipHeader.IHL = header.IPv4MinimumSize 32 | ipHeader.TOS = 0 33 | ipHeader.TotalLength = uint16(len(cp.payload) + 40) 34 | ipHeader.ID = cp.ipID 35 | ipHeader.Flags = 0b010 36 | ipHeader.FragmentOffset = 0 37 | ipHeader.TTL = 60 38 | ipHeader.Protocol = 6 39 | ipHeader.Checksum = 0 40 | ipHeader.SrcAddr = cp.srcIP.To4() 41 | ipHeader.DstAddr = cp.dstIP.To4() 42 | 43 | ipPacket.Encode(&ipHeader) 44 | ipPacket.SetChecksum(^ipPacket.CalculateChecksum()) 45 | 46 | //TCP header 47 | tcpPacket := header.TCP(result[header.IPv4MinimumSize:]) 48 | tcpHeader := header.TCPFields{} 49 | tcpHeader.SrcPort = cp.srcPort 50 | tcpHeader.DstPort = cp.dstPort 51 | tcpHeader.SeqNum = cp.seqNum 52 | tcpHeader.AckNum = cp.ackNum 53 | tcpHeader.DataOffset = header.TCPMinimumSize 54 | tcpHeader.Flags = 0 55 | if cp.syn { 56 | tcpHeader.Flags = tcpHeader.Flags | header.TCPFlagSyn 57 | } 58 | if cp.ack { 59 | tcpHeader.Flags = tcpHeader.Flags | header.TCPFlagAck 60 | } 61 | if cp.rst { 62 | tcpHeader.Flags = tcpHeader.Flags | header.TCPFlagRst 63 | } 64 | if cp.push { 65 | tcpHeader.Flags = tcpHeader.Flags | header.TCPFlagPsh 66 | } 67 | tcpHeader.WindowSize = 6543 68 | tcpHeader.Checksum = 0 69 | tcpHeader.UrgentPointer = 0 70 | 71 | tcpPacket.Encode(&tcpHeader) 72 | xsum := header.PseudoHeaderChecksum(tcp.ProtocolNumber, tcpip.Address(cp.srcIP), tcpip.Address(cp.dstIP), uint16(ipHeader.TotalLength-header.IPv4MinimumSize)) 73 | xsum = header.Checksum(cp.payload, xsum) 74 | tcpPacket.SetChecksum(^tcpPacket.CalculateChecksum(xsum)) 75 | 76 | return ipHeader.TotalLength 77 | } 78 | 79 | func (cp *ConnPacket) decode(data []byte) { 80 | ipHeader := header.IPv4(data[0:]) 81 | tcpHeader := header.TCP(data[header.IPv4MinimumSize:]) 82 | cp.ipID = ipHeader.ID() 83 | cp.srcIP = ipHeader.SourceAddress().To4() 84 | cp.dstIP = ipHeader.DestinationAddress().To4() 85 | cp.syn = tcpHeader.Flags()&header.TCPFlagSyn != 0 86 | cp.ack = tcpHeader.Flags()&header.TCPFlagAck != 0 87 | cp.rst = tcpHeader.Flags()&header.TCPFlagRst != 0 88 | cp.push = tcpHeader.Flags()&header.TCPFlagPsh != 0 89 | cp.seqNum = tcpHeader.SequenceNumber() 90 | cp.ackNum = tcpHeader.AckNumber() 91 | cp.srcPort = tcpHeader.SourcePort() 92 | cp.dstPort = tcpHeader.DestinationPort() 93 | cp.window = tcpHeader.WindowSize() 94 | ipHeaderLen := ipHeader.HeaderLength() 95 | tcpHeaderLen := tcpHeader.DataOffset() 96 | cp.payload = data[ipHeaderLen+tcpHeaderLen:] 97 | } 98 | -------------------------------------------------------------------------------- /connection/keepalive.go: -------------------------------------------------------------------------------- 1 | package connection 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "sync" 7 | "time" 8 | 9 | "github.com/sodapanda/junkwire/misc" 10 | ) 11 | 12 | type keeper struct { 13 | callback func() 14 | cc *ClientConn 15 | kpMap map[uint64]uint64 16 | dataBuffer []byte 17 | lock *sync.Mutex 18 | stopFlag bool 19 | stopChan chan string 20 | running bool 21 | } 22 | 23 | func newKeeper(cc *ClientConn, stopChan chan string, lostCallback func()) *keeper { 24 | kp := new(keeper) 25 | kp.callback = lostCallback 26 | kp.dataBuffer = make([]byte, 8) 27 | kp.lock = new(sync.Mutex) 28 | kp.cc = cc 29 | kp.stopFlag = false 30 | kp.running = false 31 | kp.stopChan = stopChan 32 | return kp 33 | } 34 | 35 | func (kp *keeper) start() { 36 | misc.PLog("kp start") 37 | kp.stopFlag = false 38 | kp.running = true 39 | for { 40 | kp.kpMap = make(map[uint64]uint64) 41 | for i := 0; i < 10; i++ { 42 | time.Sleep(100 * time.Millisecond) 43 | kp.send() 44 | } 45 | 46 | time.Sleep(1 * time.Second) 47 | 48 | kp.lock.Lock() 49 | lossCount := 0 50 | for _, rtt := range kp.kpMap { 51 | if rtt == 0 { 52 | lossCount++ 53 | } 54 | } 55 | kp.lock.Unlock() 56 | if lossCount > 9 { 57 | misc.PLog("disconnect! keep alive loss") 58 | kp.callback() 59 | break 60 | } 61 | if kp.stopFlag { 62 | break 63 | } 64 | } 65 | kp.running = false 66 | 67 | misc.PLog("kp loop break") 68 | kp.stopChan <- "kpstop" 69 | misc.PLog("kp chan send") 70 | } 71 | 72 | func (kp *keeper) send() { 73 | kp.lock.Lock() 74 | defer kp.lock.Unlock() 75 | unixNano := time.Now().UnixNano() 76 | binary.BigEndian.PutUint64(kp.dataBuffer, uint64(unixNano)) 77 | kp.cc.Write(kp.dataBuffer, true) 78 | kp.kpMap[uint64(unixNano)] = 0 79 | } 80 | 81 | func (kp *keeper) rcv(timeStamp uint64) { 82 | kp.lock.Lock() 83 | kp.lock.Unlock() 84 | unixNano := time.Now().UnixNano() 85 | rtt := uint64(unixNano) - timeStamp 86 | if _, ok := kp.kpMap[timeStamp]; ok { 87 | kp.kpMap[timeStamp] = rtt 88 | } else { 89 | misc.PLog(fmt.Sprintf("kp map has no key %d", timeStamp)) 90 | } 91 | } 92 | 93 | func (kp *keeper) stop() { 94 | misc.PLog("stop called") 95 | kp.lock.Lock() 96 | defer kp.lock.Unlock() 97 | if kp.running { 98 | kp.stopFlag = true 99 | } else { 100 | misc.PLog(" kp not running ") 101 | if kp.stopChan != nil { 102 | misc.PLog(" kp send chan in stop") 103 | kp.stopChan <- "stop" 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /connection/server.go: -------------------------------------------------------------------------------- 1 | package connection 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | 7 | "github.com/google/netstack/tcpip" 8 | ds "github.com/sodapanda/junkwire/datastructure" 9 | "github.com/sodapanda/junkwire/device" 10 | "github.com/sodapanda/junkwire/misc" 11 | ) 12 | 13 | //ServerConnHandler handler callback 14 | type ServerConnHandler interface { 15 | OnData([]byte, *ServerConn) 16 | OnDisconnect() 17 | } 18 | 19 | //ServerConn server connection 20 | type ServerConn struct { 21 | tun *device.TunInterface 22 | srcIP tcpip.Address 23 | dstIP tcpip.Address 24 | srcPort uint16 25 | dstPort uint16 26 | payloadsFromUpLayer *ds.BlockingQueue 27 | lastRcvSeq uint32 28 | lastRcvAck uint32 29 | lastRcvLen uint32 30 | fsm *ds.Fsm 31 | sendID uint16 32 | handler ServerConnHandler 33 | pool *ds.DataBufferPool 34 | } 35 | 36 | //NewServerConn create server connection 37 | func NewServerConn(srcIP string, srcPort uint16, tun *device.TunInterface, qLen int) *ServerConn { 38 | sc := new(ServerConn) 39 | sc.tun = tun 40 | sc.srcIP = tcpip.Address(net.ParseIP(srcIP).To4()) 41 | sc.srcPort = srcPort 42 | sc.payloadsFromUpLayer = ds.NewBlockingQueue(qLen) 43 | sc.pool = ds.NewDataBufferPool() 44 | 45 | sc.fsm = ds.NewFsm("stop") 46 | 47 | sc.fsm.AddRule("stop", ds.Event{Name: "start"}, "waitsyn", func(et ds.Event) { 48 | misc.PLog("server wait syn") 49 | }) 50 | 51 | sc.fsm.AddRule("waitsyn", ds.Event{Name: "rcvsyn"}, "gotSyn", func(et ds.Event) { 52 | misc.PLog("server got syn then send syn ack") 53 | cp := et.ConnPacket.(ConnPacket) 54 | sc.dstIP = cp.srcIP 55 | sc.dstPort = cp.srcPort 56 | 57 | cp = ConnPacket{} 58 | cp.syn = true 59 | cp.ack = true 60 | cp.srcIP = sc.srcIP 61 | cp.dstIP = sc.dstIP 62 | cp.srcPort = sc.srcPort 63 | misc.PLog(fmt.Sprintf(" %s:%d", sc.dstIP.String(), sc.dstPort)) 64 | cp.dstPort = sc.dstPort 65 | cp.seqNum = sc.lastRcvAck 66 | cp.ackNum = sc.lastRcvSeq + sc.lastRcvLen 67 | cp.payload = nil 68 | result := make([]byte, 40) 69 | cp.encode(result) 70 | sc.tun.Write(result) 71 | sc.sendID++ 72 | sc.fsm.OnEvent(ds.Event{Name: "sdsynack"}) 73 | }) 74 | 75 | sc.fsm.AddRule("waitsyn", ds.Event{Name: "rcvack"}, "waitsyn", func(et ds.Event) { 76 | misc.PLog("waitsyn rcvack. Stay") 77 | }) 78 | 79 | sc.fsm.AddRule("waitsyn", ds.Event{Name: "rcvrst"}, "waitsyn", func(et ds.Event) { 80 | misc.PLog("wait syn got rst. Stay") 81 | }) 82 | 83 | sc.fsm.AddRule("gotSyn", ds.Event{Name: "sdsynack"}, "synacksd", func(et ds.Event) { 84 | misc.PLog("syn ack sent") 85 | }) 86 | 87 | sc.fsm.AddRule("synacksd", ds.Event{Name: "rcvsyn"}, "gotSyn", func(et ds.Event) { 88 | misc.PLog("\nsynacksd rcvsyn,new peer!") 89 | 90 | cp := et.ConnPacket.(ConnPacket) 91 | sc.dstIP = cp.srcIP 92 | sc.dstPort = cp.srcPort 93 | 94 | cp = ConnPacket{} 95 | cp.syn = true 96 | cp.ack = true 97 | cp.srcIP = sc.srcIP 98 | cp.dstIP = sc.dstIP 99 | cp.srcPort = sc.srcPort 100 | misc.PLog(fmt.Sprintf(" %s:%d", sc.dstIP.String(), sc.dstPort)) //上面被换过 101 | cp.dstPort = sc.dstPort 102 | cp.seqNum = sc.lastRcvAck 103 | cp.ackNum = sc.lastRcvSeq + sc.lastRcvLen 104 | cp.payload = nil 105 | result := make([]byte, 40) 106 | cp.encode(result) 107 | sc.tun.Write(result) 108 | sc.sendID = 0 109 | sc.fsm.OnEvent(ds.Event{Name: "sdsynack"}) 110 | }) 111 | 112 | sc.fsm.AddRule("synacksd", ds.Event{Name: "rcvack"}, "estb", func(et ds.Event) { 113 | misc.PLog("server estab") 114 | cp := et.ConnPacket.(ConnPacket) 115 | if cp.payload != nil && len(cp.payload) > 0 { 116 | sc.handler.OnData(cp.payload, sc) 117 | } 118 | }) 119 | 120 | sc.fsm.AddRule("synacksd", ds.Event{Name: "rcvrst"}, "waitsyn", func(et ds.Event) { 121 | misc.PLog("synacksd rcvrst,to waitsyn") 122 | }) 123 | 124 | sc.fsm.AddRule("estb", ds.Event{Name: "rcvsyn"}, "gotSyn", func(et ds.Event) { 125 | misc.PLog("\nestb rcvsyn,new peer!") 126 | cp := et.ConnPacket.(ConnPacket) 127 | sc.dstIP = cp.srcIP 128 | sc.dstPort = cp.srcPort 129 | 130 | cp = ConnPacket{} 131 | cp.syn = true 132 | cp.ack = true 133 | cp.srcIP = sc.srcIP 134 | cp.dstIP = sc.dstIP 135 | cp.srcPort = sc.srcPort 136 | misc.PLog(fmt.Sprintf(" %s:%d", sc.dstIP.String(), sc.dstPort)) 137 | cp.dstPort = sc.dstPort 138 | cp.seqNum = sc.lastRcvAck 139 | cp.ackNum = sc.lastRcvSeq + sc.lastRcvLen 140 | cp.payload = nil 141 | result := make([]byte, 40) 142 | cp.encode(result) 143 | sc.tun.Write(result) 144 | sc.sendID = 0 145 | sc.fsm.OnEvent(ds.Event{Name: "sdsynack"}) 146 | }) 147 | 148 | sc.fsm.AddRule("estb", ds.Event{Name: "rcvack"}, "estb", func(et ds.Event) { 149 | cp := et.ConnPacket.(ConnPacket) 150 | if cp.payload != nil && len(cp.payload) > 0 { 151 | sc.handler.OnData(cp.payload, sc) 152 | } 153 | }) 154 | 155 | sc.fsm.AddRule("estb", ds.Event{Name: "rcvrst"}, "waitsyn", func(et ds.Event) { 156 | misc.PLog("estb rcvrst,to waitsyn") 157 | }) 158 | 159 | sc.fsm.AddRule("error", ds.Event{Name: "sdrst"}, "waitsyn", func(et ds.Event) { 160 | misc.PLog("return to wait syn") 161 | }) 162 | 163 | sc.fsm.OnEvent(ds.Event{Name: "start"}) 164 | 165 | go sc.q2Tun() 166 | go sc.readLoop() 167 | return sc 168 | } 169 | 170 | //AddHandler add handler callback 171 | func (sc *ServerConn) AddHandler(handler ServerConnHandler) { 172 | sc.handler = handler 173 | } 174 | 175 | func (sc *ServerConn) readLoop() { 176 | for { 177 | dataBuffer := sc.tun.Read() 178 | cp := ConnPacket{} 179 | if dataBuffer == nil || dataBuffer.Length == 0 { 180 | misc.PLog("server conn loop exit") 181 | return 182 | } 183 | cp.decode(dataBuffer.Data[:dataBuffer.Length]) 184 | 185 | //不是syn包,并且不是当前peer的ip和port就丢掉 186 | if !cp.syn && cp.srcIP != sc.dstIP { 187 | misc.PLog("packet not from peer.drop") 188 | misc.PLog(fmt.Sprintf(" %s:%d", cp.srcIP.String(), cp.srcPort)) 189 | sc.tun.Recycle(dataBuffer) 190 | continue 191 | } 192 | 193 | if cp.window != 6543 { 194 | misc.PLog("read window is not 6543!!Danger.Drop") 195 | misc.PLog(fmt.Sprintf(" %s:%d win:%d\n", cp.srcIP.String(), cp.srcPort, cp.window)) 196 | continue 197 | } 198 | sc.lastRcvSeq = cp.seqNum 199 | sc.lastRcvAck = cp.ackNum 200 | sc.lastRcvLen = uint32(len(cp.payload)) 201 | if cp.syn { 202 | sc.lastRcvLen = 1 203 | } 204 | 205 | //心跳包 如果不是在estb状态 不要回应心跳 206 | if cp.push { 207 | if sc.fsm.Current != "estb" { 208 | continue 209 | } 210 | sc.Write(cp.payload, true) 211 | sc.tun.Recycle(dataBuffer) 212 | continue 213 | } 214 | et := ds.Event{} 215 | if cp.syn { 216 | et.Name = "rcvsyn" 217 | } 218 | if cp.ack { 219 | et.Name = "rcvack" 220 | } 221 | if cp.rst { 222 | et.Name = "rcvrst" 223 | } 224 | et.ConnPacket = cp 225 | sc.fsm.OnEvent(et) 226 | sc.tun.Recycle(dataBuffer) 227 | } 228 | } 229 | 230 | func (sc *ServerConn) reset() { 231 | misc.PLog("send reset") 232 | cp := ConnPacket{} 233 | cp.syn = false 234 | cp.ack = false 235 | cp.rst = true 236 | cp.srcIP = sc.srcIP 237 | cp.dstIP = sc.dstIP 238 | cp.srcPort = sc.srcPort 239 | cp.dstPort = sc.dstPort 240 | cp.seqNum = sc.lastRcvAck 241 | cp.ackNum = sc.lastRcvSeq + sc.lastRcvLen 242 | cp.payload = nil 243 | result := make([]byte, 40) 244 | cp.encode(result) 245 | sc.tun.Write(result) 246 | sc.sendID = 0 247 | } 248 | 249 | func (sc *ServerConn) Write(data []byte, isKp bool) { 250 | dbf := sc.pool.PoolGet() 251 | cp := ConnPacket{} 252 | cp.ipID = sc.sendID 253 | sc.sendID++ 254 | cp.srcIP = sc.srcIP 255 | cp.dstIP = sc.dstIP 256 | cp.srcPort = sc.srcPort 257 | cp.dstPort = sc.dstPort 258 | cp.syn = false 259 | cp.ack = true 260 | cp.rst = false 261 | if isKp { 262 | cp.push = true 263 | } 264 | cp.seqNum = sc.lastRcvAck 265 | cp.ackNum = sc.lastRcvSeq + sc.lastRcvLen 266 | cp.payload = data 267 | length := cp.encode(dbf.Data) 268 | dbf.Length = int(length) 269 | sc.payloadsFromUpLayer.Put(dbf) 270 | } 271 | 272 | func (sc *ServerConn) q2Tun() { 273 | for { 274 | dbf := sc.payloadsFromUpLayer.Get() 275 | data := dbf.Data[:dbf.Length] 276 | cp := ConnPacket{} 277 | cp.decode(data) 278 | if cp.dstIP != sc.dstIP { 279 | misc.PLog("write not to peer.Drop") 280 | sc.pool.PoolPut(dbf) 281 | continue 282 | } 283 | sc.tun.Write(data) 284 | sc.pool.PoolPut(dbf) 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /datastructure/dataBuffer.go: -------------------------------------------------------------------------------- 1 | package datastructure 2 | 3 | import "sync" 4 | 5 | //DataBuffer byte slice and length,从pool里取出来,然后装入不同长度的内容之后放入队列 6 | type DataBuffer struct { 7 | Data []byte 8 | Length int 9 | Tag string 10 | } 11 | 12 | type DataBufferPool struct { 13 | dataPool sync.Pool 14 | } 15 | 16 | func NewDataBufferPool() *DataBufferPool { 17 | pool := new(DataBufferPool) 18 | pool.dataPool = sync.Pool{ 19 | New: func() interface{} { 20 | data := new(DataBuffer) 21 | data.Data = make([]byte, 2000) 22 | return data 23 | }, 24 | } 25 | return pool 26 | } 27 | 28 | func (dp *DataBufferPool) PoolGet() *DataBuffer { 29 | item := dp.dataPool.Get() 30 | return item.(*DataBuffer) 31 | } 32 | 33 | func (dp *DataBufferPool) PoolPut(item *DataBuffer) { 34 | dp.dataPool.Put(item) 35 | } 36 | -------------------------------------------------------------------------------- /datastructure/fsm.go: -------------------------------------------------------------------------------- 1 | package datastructure 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/sodapanda/junkwire/misc" 7 | ) 8 | 9 | //State 状态 10 | type State struct { 11 | name string 12 | trans map[string]trans //key是event value是state的name 13 | } 14 | 15 | //Event trans event 16 | type Event struct { 17 | Name string 18 | ConnPacket interface{} 19 | } 20 | 21 | type trans struct { 22 | name string //to state 23 | action func(Event) //action after trans 24 | } 25 | 26 | //Fsm 状态机 27 | type Fsm struct { 28 | states map[string]*State //key是state的name value是state指针 29 | Current string //currentEvent 30 | } 31 | 32 | //NewFsm 创建 33 | func NewFsm(init string) *Fsm { 34 | m := new(Fsm) 35 | m.Current = init 36 | m.states = make(map[string]*State) 37 | return m 38 | } 39 | 40 | //AddRule 添加规则 41 | func (m *Fsm) AddRule(state string, event Event, toState string, action func(Event)) { 42 | if m.states[state] == nil { 43 | m.states[state] = new(State) 44 | m.states[state].name = state 45 | m.states[state].trans = make(map[string]trans) 46 | } 47 | m.states[state].trans[event.Name] = trans{name: toState, action: action} 48 | } 49 | 50 | //OnEvent 事件发生的回调 51 | func (m *Fsm) OnEvent(event Event) { 52 | currentState := m.states[m.Current] 53 | nextTrans, ok := currentState.trans[event.Name] 54 | if !ok { 55 | eventName := event.Name 56 | if eventName == "" { 57 | eventName = "nil" 58 | } 59 | misc.PLog(fmt.Sprintf("stata:%s has no event %s\n", currentState.name, eventName)) 60 | return 61 | } 62 | nextStateName := nextTrans.name 63 | m.Current = nextStateName 64 | nextTrans.action(event) 65 | } 66 | -------------------------------------------------------------------------------- /datastructure/linkedBlockingQueue.go: -------------------------------------------------------------------------------- 1 | package datastructure 2 | 3 | import ( 4 | "container/list" 5 | "time" 6 | 7 | "sync" 8 | 9 | "github.com/sodapanda/junkwire/misc" 10 | ) 11 | 12 | //BlockingQueue 阻塞队列 13 | type BlockingQueue struct { 14 | lock *sync.Mutex 15 | capacity int 16 | notEmpty *sync.Cond 17 | notFull *sync.Cond 18 | dataList *list.List 19 | interrupt bool 20 | size int 21 | } 22 | 23 | //NewBlockingQueue 创建队列 24 | func NewBlockingQueue(capacity int) *BlockingQueue { 25 | q := new(BlockingQueue) 26 | q.lock = new(sync.Mutex) 27 | q.capacity = capacity 28 | q.notEmpty = sync.NewCond(q.lock) 29 | q.notFull = sync.NewCond(q.lock) 30 | q.dataList = list.New() 31 | q.interrupt = false 32 | q.size = 0 33 | return q 34 | } 35 | 36 | //Put put item,block if full 37 | func (q *BlockingQueue) Put(data *DataBuffer) { 38 | q.lock.Lock() 39 | defer q.lock.Unlock() 40 | for q.size == q.capacity && !q.interrupt { 41 | q.notFull.Wait() 42 | } 43 | if q.interrupt { 44 | q.interrupt = false 45 | misc.PLog("return from interrupted Put") 46 | return 47 | } 48 | q.dataList.PushBack(data) 49 | q.size++ 50 | q.notEmpty.Signal() 51 | } 52 | 53 | //Get item block if empty,return nil if interrupted 54 | func (q *BlockingQueue) Get() *DataBuffer { 55 | q.lock.Lock() 56 | defer q.lock.Unlock() 57 | 58 | for q.size == 0 && !q.interrupt { 59 | q.notEmpty.Wait() 60 | } 61 | if q.interrupt { 62 | q.interrupt = false 63 | return nil 64 | } 65 | element := q.dataList.Back() 66 | rst := element.Value.(*DataBuffer) 67 | q.size-- 68 | q.dataList.Remove(element) 69 | q.notFull.Signal() 70 | return rst 71 | } 72 | 73 | //Interrupt stop 74 | func (q *BlockingQueue) Interrupt() { 75 | q.lock.Lock() 76 | defer q.lock.Unlock() 77 | q.interrupt = true 78 | q.notEmpty.Signal() 79 | q.notFull.Signal() 80 | misc.PLog("interrupt called") 81 | } 82 | 83 | //GetWithTimeout Get item,block with given time 84 | func (q *BlockingQueue) GetWithTimeout(timeout time.Duration) *DataBuffer { 85 | q.lock.Lock() 86 | defer q.lock.Unlock() 87 | tm := time.NewTimer(timeout) 88 | chann := make(chan int, 1) 89 | isTimeout := false 90 | 91 | go func() { 92 | for q.size == 0 && !isTimeout { 93 | q.notEmpty.Wait() 94 | } 95 | chann <- 1 96 | }() 97 | 98 | select { 99 | case <-chann: 100 | element := q.dataList.Back() 101 | rst := element.Value.(*DataBuffer) 102 | q.size-- 103 | q.dataList.Remove(element) 104 | q.notFull.Signal() 105 | defer tm.Stop() 106 | return rst 107 | case <-tm.C: 108 | isTimeout = true 109 | q.notEmpty.Signal() 110 | <-chann 111 | return nil 112 | } 113 | } 114 | 115 | //GetSize get current size 116 | func (q *BlockingQueue) GetSize() int { 117 | q.lock.Lock() 118 | defer q.lock.Unlock() 119 | return q.size 120 | } 121 | -------------------------------------------------------------------------------- /device/interface.go: -------------------------------------------------------------------------------- 1 | package device 2 | 3 | import ( 4 | "os/exec" 5 | "time" 6 | 7 | ds "github.com/sodapanda/junkwire/datastructure" 8 | "github.com/sodapanda/junkwire/misc" 9 | "github.com/songgao/water" 10 | ) 11 | 12 | //TunInterface tun device 13 | type TunInterface struct { 14 | name string 15 | tun *water.Interface 16 | queue *ds.BlockingQueue 17 | pool *ds.DataBufferPool 18 | } 19 | 20 | //NewTunInterface 创建tun设备 21 | func NewTunInterface(interfaceName string, address string, queueLen int) *TunInterface { 22 | d := new(TunInterface) 23 | conf := water.Config{ 24 | DeviceType: water.TUN, 25 | } 26 | conf.Name = interfaceName 27 | d.tun, _ = water.New(conf) 28 | 29 | cmd := exec.Command("sudo", "ip", "address", "add", address+"/24", "dev", interfaceName) 30 | cmd.Run() 31 | cmd = exec.Command("sudo", "ip", "link", "set", "up", "dev", interfaceName) 32 | cmd.Run() 33 | 34 | d.queue = ds.NewBlockingQueue(queueLen) 35 | d.pool = ds.NewDataBufferPool() 36 | 37 | go d.turnUp() 38 | return d 39 | } 40 | 41 | func (d *TunInterface) turnUp() { 42 | for { 43 | dbf := d.pool.PoolGet() 44 | length, err := d.tun.Read(dbf.Data) 45 | misc.CheckErr(err) 46 | dbf.Length = length 47 | d.queue.Put(dbf) 48 | } 49 | } 50 | 51 | func (d *TunInterface) Read() *ds.DataBuffer { 52 | dbf := d.queue.Get() 53 | return dbf 54 | } 55 | 56 | func (d *TunInterface) Interrupt() { 57 | d.queue.Interrupt() 58 | } 59 | 60 | func (d *TunInterface) Recycle(dbf *ds.DataBuffer) { 61 | d.pool.PoolPut(dbf) 62 | } 63 | 64 | func (d *TunInterface) Write(data []byte) (int, error) { 65 | return d.tun.Write(data) 66 | } 67 | 68 | func (d *TunInterface) ReadTimeout(timeout time.Duration) *ds.DataBuffer { 69 | dbf := d.queue.GetWithTimeout(timeout) 70 | return dbf 71 | } 72 | 73 | func (d *TunInterface) ClearQueue() { 74 | for d.queue.GetSize() != 0 { 75 | dbf := d.queue.Get() 76 | d.pool.PoolPut(dbf) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /fec.json: -------------------------------------------------------------------------------- 1 | { 2 | "mode": "client", 3 | "queue": 5, 4 | "client": { 5 | "tun": { 6 | "deviceIP": "10.1.1.1", 7 | "port": "8978", 8 | "srcIP": "10.1.1.2", 9 | "peers": [ 10 | { 11 | "ip": "1.1.1.1", 12 | "port": "17020" 13 | } 14 | ] 15 | }, 16 | "socket": { 17 | "listenPort": "21007" 18 | } 19 | }, 20 | "fec": { 21 | "enable": true, 22 | "seg": 20, 23 | "parity": 10, 24 | "stageTimeout": 8, 25 | "duration": 20, 26 | "cap": 500, 27 | "row": 1000 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sodapanda/junkwire 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/google/btree v1.0.0 // indirect 7 | github.com/google/netstack v0.0.0-20191123085552-55fcc16cd0eb 8 | github.com/klauspost/reedsolomon v1.9.9 9 | github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 10 | golang.org/x/sys v0.0.0-20200922070232-aee5d888a860 // indirect 11 | golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= 2 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 3 | github.com/google/netstack v0.0.0-20191123085552-55fcc16cd0eb h1:/YcrD0GSdU5gtckXHVjSEd0Y6VgboNW7VYyImZS3y6g= 4 | github.com/google/netstack v0.0.0-20191123085552-55fcc16cd0eb/go.mod h1:r/rILWg3r1Qy9G1IFMhsqWLq2GjwuYoTuPgG7ckMAjk= 5 | github.com/klauspost/cpuid v1.2.4 h1:EBfaK0SWSwk+fgk6efYFWdzl8MwRWoOO1gkmiaTXPW4= 6 | github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 7 | github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54= 8 | github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo= 9 | github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= 10 | github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= 11 | golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a h1:i47hUS795cOydZI4AwJQCKXOr4BvxzvikwDoDtHhP2Y= 12 | golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 13 | golang.org/x/sys v0.0.0-20200922070232-aee5d888a860 h1:YEu4SMq7D0cmT7CBbXfcH0NZeuChAXwsHe/9XueUO6o= 14 | golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 15 | golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= 16 | golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 17 | -------------------------------------------------------------------------------- /jw_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | "github.com/sodapanda/junkwire/codec" 9 | ) 10 | 11 | func TestInterlace(t *testing.T) { 12 | seg := 5 13 | icodec := codec.NewFecCodec(seg, 10, 100) 14 | rstBf := make([]byte, 2000*seg) 15 | sb := codec.NewStageBuffer(icodec, seg, rstBf, 1*time.Second, func(sb *codec.StageBuffer, rst []byte, realLen int) { 16 | fmt.Println("callback ", realLen) 17 | }) 18 | 19 | //1 20 | content := make([]byte, 10) 21 | sb.Append(content, uint16(10)) 22 | 23 | //2 24 | content = make([]byte, 10) 25 | sb.Append(content, uint16(10)) 26 | 27 | //3 28 | content = make([]byte, 10) 29 | sb.Append(content, uint16(10)) 30 | 31 | //4 32 | content = make([]byte, 10) 33 | sb.Append(content, uint16(10)) 34 | 35 | //5 36 | content = make([]byte, 10) 37 | sb.Append(content, uint16(10)) 38 | 39 | //6 40 | content = make([]byte, 11) 41 | sb.Append(content, uint16(11)) 42 | 43 | time.Sleep(100 * time.Second) 44 | } 45 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "encoding/json" 6 | "flag" 7 | "fmt" 8 | "io/ioutil" 9 | "math/rand" 10 | "net/http" 11 | _ "net/http/pprof" 12 | "os" 13 | "strconv" 14 | "time" 15 | 16 | "github.com/sodapanda/junkwire/application" 17 | "github.com/sodapanda/junkwire/codec" 18 | "github.com/sodapanda/junkwire/connection" 19 | "github.com/sodapanda/junkwire/device" 20 | "github.com/sodapanda/junkwire/misc" 21 | ) 22 | 23 | var mCodec *codec.FecCodec 24 | 25 | func main() { 26 | go ctlServer() 27 | 28 | fConfigPath := flag.String("c", "config.json", "config file path") 29 | flag.Parse() 30 | configPath := *fConfigPath 31 | 32 | configFile, err := os.Open(configPath) 33 | misc.CheckErr(err) 34 | defer configFile.Close() 35 | configByte, _ := ioutil.ReadAll(configFile) 36 | mConfig := new(Config) 37 | json.Unmarshal(configByte, mConfig) 38 | 39 | misc.Init(mConfig.LogFile) 40 | misc.PLog("start") 41 | 42 | isServer := mConfig.Mode == "server" 43 | 44 | if isServer { 45 | server(mConfig) 46 | } else { 47 | client(mConfig) 48 | } 49 | } 50 | 51 | func ctlServer() { 52 | http.HandleFunc("/log", func(w http.ResponseWriter, r *http.Request) { 53 | fmt.Fprintf(w, mCodec.Dump()) 54 | }) 55 | 56 | http.HandleFunc("/lenkind", func(w http.ResponseWriter, r *http.Request) { 57 | fmt.Fprintf(w, mCodec.DumpLenKind()) 58 | }) 59 | http.ListenAndServe(":8080", nil) 60 | } 61 | 62 | func client(config *Config) { 63 | tun := device.NewTunInterface(config.Name, config.Client.Tun.DeviceIP, 100) 64 | 65 | fmt.Printf("qlen:%d,go?", config.QueueLen) 66 | reader := bufio.NewReader(os.Stdin) 67 | reader.ReadString('\n') 68 | fmt.Println("start,please see log") 69 | 70 | var client application.IClient 71 | if config.Fec.Enable { 72 | misc.PLog("fec enable") 73 | codec := codec.NewFecCodec(config.Fec.Seg, config.Fec.Parity, config.Fec.Cap) 74 | mCodec = codec 75 | client = application.NewAppClientFec(config.Client.Socket.ListenPort, config.Fec.Seg, config.Fec.Parity, codec, config.Fec.Duration, config.Fec.Row, config.Fec.StageTimeout) 76 | } else { 77 | client = application.NewAppClient(config.Client.Socket.ListenPort) 78 | } 79 | client.Start() 80 | srcPort, _ := strconv.Atoi(config.Client.Tun.Port) 81 | 82 | connTimes := -1 83 | for { 84 | connTimes++ 85 | if connTimes >= len(config.Client.Tun.Peers) { 86 | connTimes = 0 87 | } 88 | serConf := config.Client.Tun.Peers[connTimes] 89 | serPort, _ := strconv.Atoi(serConf.Port) 90 | 91 | //防止一只重复使用一个src port 可能对nat有好处 92 | rdm := rand.Intn(10000) 93 | srcPort = srcPort + rdm 94 | 95 | cc := connection.NewClientConn(tun, config.Client.Tun.SrcIP, serConf.IP, uint16(srcPort), uint16(serPort), config.QueueLen) 96 | client.SetClientConn(cc) 97 | cc.WaitStop() 98 | client.SetClientConn(nil) 99 | misc.PLog("client main loop stop restart") 100 | time.Sleep(1 * time.Second) 101 | } 102 | } 103 | 104 | func server(config *Config) { 105 | tun := device.NewTunInterface(config.Name, config.Server.Tun.DeviceIP, 100) 106 | 107 | fmt.Printf("qlen:%d,go?", config.QueueLen) 108 | reader := bufio.NewReader(os.Stdin) 109 | reader.ReadString('\n') 110 | fmt.Println("start,please see log") 111 | 112 | serPort, _ := strconv.Atoi(config.Server.Tun.Port) 113 | 114 | sc := connection.NewServerConn(config.Server.Tun.SrcIP, uint16(serPort), tun, config.QueueLen) 115 | 116 | var sv application.IServer 117 | if config.Fec.Enable { 118 | misc.PLog("fec enable") 119 | codec := codec.NewFecCodec(config.Fec.Seg, config.Fec.Parity, config.Fec.Cap) 120 | mCodec = codec 121 | sv = application.NewAppServerFec(config.Server.Socket.DstIP, config.Server.Socket.DstPort, sc, config.Fec.Seg, config.Fec.Parity, codec, config.Fec.Duration, config.Fec.Row, config.Fec.StageTimeout) 122 | } else { 123 | sv = application.NewAppServer(config.Server.Socket.DstIP, config.Server.Socket.DstPort, sc) 124 | } 125 | sv.Start() 126 | reader = bufio.NewReader(os.Stdin) 127 | reader.ReadString('\n') 128 | } 129 | 130 | //Config config 131 | type Config struct { 132 | Name string `json:"name"` 133 | Mode string `json:"mode"` 134 | QueueLen int `json:"queue"` 135 | LogFile string `json:"logFile"` 136 | Server struct { 137 | Tun struct { 138 | DeviceIP string `json:"deviceIP"` 139 | Port string `json:"port"` 140 | SrcIP string `json:"srcIP"` 141 | } `json:"tun"` 142 | Socket struct { 143 | DstIP string `json:"dstIP"` 144 | DstPort string `json:"dstPort"` 145 | } `json:"socket"` 146 | } `json:"server"` 147 | Client struct { 148 | Tun struct { 149 | DeviceIP string `json:"deviceIP"` 150 | Port string `json:"port"` 151 | SrcIP string `json:"srcIP"` 152 | Peers []struct { 153 | IP string `json:"ip"` 154 | Port string `json:"port"` 155 | } `json:"peers"` 156 | } `json:"tun"` 157 | Socket struct { 158 | ListenPort string `json:"listenPort"` 159 | } `json:"socket"` 160 | } `json:"client"` 161 | Fec struct { 162 | Enable bool `json:"enable"` 163 | Seg int `json:"seg"` 164 | Parity int `json:"parity"` 165 | StageTimeout int `json:"stageTimeout"` 166 | Duration int `json:"duration"` 167 | Cap int `json:"cap"` 168 | Row int `json:"row"` 169 | } `json:"fec"` 170 | } 171 | -------------------------------------------------------------------------------- /misc/misc.go: -------------------------------------------------------------------------------- 1 | package misc 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | ) 8 | 9 | //CheckErr check error 10 | func CheckErr(e error) { 11 | if e != nil { 12 | fmt.Println(e.Error()) 13 | os.Exit(-1) 14 | } 15 | } 16 | 17 | var logger *log.Logger 18 | 19 | //Init init 20 | func Init(logfile string) { 21 | f, err := os.OpenFile(logfile, 22 | os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) 23 | if err != nil { 24 | fmt.Println(err.Error()) 25 | } 26 | 27 | logger = log.New(f, "", log.LstdFlags) 28 | } 29 | 30 | //PLog print long 31 | func PLog(msg string) { 32 | logger.Println(msg) 33 | } 34 | -------------------------------------------------------------------------------- /netconfig: -------------------------------------------------------------------------------- 1 | sysctl -p 2 | iptables -t nat -A POSTROUTING -s 10.1.1.2 -p tcp -o eno1 -j SNAT --to-source 192.168.8.39 3 | -------------------------------------------------------------------------------- /profile001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodapanda/junkwire/0c8a44efdf92c767af670074e74ce4d2df265e7c/profile001.png -------------------------------------------------------------------------------- /profile002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodapanda/junkwire/0c8a44efdf92c767af670074e74ce4d2df265e7c/profile002.png --------------------------------------------------------------------------------