aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/xtaci
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/xtaci')
-rw-r--r--vendor/github.com/xtaci/kcp-go/.gitignore24
-rw-r--r--vendor/github.com/xtaci/kcp-go/.travis.yml15
-rw-r--r--vendor/github.com/xtaci/kcp-go/LICENSE22
-rw-r--r--vendor/github.com/xtaci/kcp-go/README.md92
-rw-r--r--vendor/github.com/xtaci/kcp-go/crypt.go263
-rw-r--r--vendor/github.com/xtaci/kcp-go/donate.pngbin0 -> 4420 bytes
-rw-r--r--vendor/github.com/xtaci/kcp-go/fec.go236
-rw-r--r--vendor/github.com/xtaci/kcp-go/frame.pngbin0 -> 8179 bytes
-rw-r--r--vendor/github.com/xtaci/kcp-go/kcp.go978
-rw-r--r--vendor/github.com/xtaci/kcp-go/sess.go936
-rw-r--r--vendor/github.com/xtaci/kcp-go/shannon.jpgbin0 -> 52964 bytes
-rw-r--r--vendor/github.com/xtaci/kcp-go/snmp.go63
-rw-r--r--vendor/github.com/xtaci/kcp-go/xor.go111
-rw-r--r--vendor/github.com/xtaci/smux/.gitignore24
-rw-r--r--vendor/github.com/xtaci/smux/.travis.yml15
-rw-r--r--vendor/github.com/xtaci/smux/LICENSE21
-rw-r--r--vendor/github.com/xtaci/smux/README.md99
-rw-r--r--vendor/github.com/xtaci/smux/curve.jpgbin0 -> 106626 bytes
-rw-r--r--vendor/github.com/xtaci/smux/frame.go60
-rw-r--r--vendor/github.com/xtaci/smux/mux.go80
-rw-r--r--vendor/github.com/xtaci/smux/mux.jpgbin0 -> 6199 bytes
-rw-r--r--vendor/github.com/xtaci/smux/session.go350
-rw-r--r--vendor/github.com/xtaci/smux/smux.pngbin0 -> 9891 bytes
-rw-r--r--vendor/github.com/xtaci/smux/stream.go262
24 files changed, 3651 insertions, 0 deletions
diff --git a/vendor/github.com/xtaci/kcp-go/.gitignore b/vendor/github.com/xtaci/kcp-go/.gitignore
new file mode 100644
index 0000000..daf913b
--- /dev/null
+++ b/vendor/github.com/xtaci/kcp-go/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/vendor/github.com/xtaci/kcp-go/.travis.yml b/vendor/github.com/xtaci/kcp-go/.travis.yml
new file mode 100644
index 0000000..875d28d
--- /dev/null
+++ b/vendor/github.com/xtaci/kcp-go/.travis.yml
@@ -0,0 +1,15 @@
+language: go
+go:
+ - tip
+
+before_install:
+ - go get -t -v ./...
+
+install:
+ - go get github.com/xtaci/kcp-go
+
+script:
+ - go test -coverprofile=coverage.txt -covermode=atomic -bench .
+
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/github.com/xtaci/kcp-go/LICENSE b/vendor/github.com/xtaci/kcp-go/LICENSE
new file mode 100644
index 0000000..8294d13
--- /dev/null
+++ b/vendor/github.com/xtaci/kcp-go/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Daniel Fu
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/vendor/github.com/xtaci/kcp-go/README.md b/vendor/github.com/xtaci/kcp-go/README.md
new file mode 100644
index 0000000..d02eee5
--- /dev/null
+++ b/vendor/github.com/xtaci/kcp-go/README.md
@@ -0,0 +1,92 @@
+# kcp-go
+
+[![GoDoc][1]][2] [![Powered][9]][10] [![MIT licensed][11]][12] [![Build Status][3]][4] [![Go Report Card][5]][6] [![Coverage Statusd][7]][8]
+
+[1]: https://godoc.org/github.com/xtaci/kcp-go?status.svg
+[2]: https://godoc.org/github.com/xtaci/kcp-go
+[3]: https://travis-ci.org/xtaci/kcp-go.svg?branch=master
+[4]: https://travis-ci.org/xtaci/kcp-go
+[5]: https://goreportcard.com/badge/github.com/xtaci/kcp-go
+[6]: https://goreportcard.com/report/github.com/xtaci/kcp-go
+[7]: https://codecov.io/gh/xtaci/kcp-go/branch/master/graph/badge.svg
+[8]: https://codecov.io/gh/xtaci/kcp-go
+[9]: https://img.shields.io/badge/KCP-Powered-blue.svg
+[10]: https://github.com/skywind3000/kcp
+[11]: https://img.shields.io/badge/license-MIT-blue.svg
+[12]: LICENSE
+
+[![Claude_Shannon](shannon.jpg)](https://en.wikipedia.org/wiki/Claude_Shannon)
+
+## Introduction
+
+kcp-go is a full-featured ***reliable-UDP*** library for golang. It provides ***reliable, ordered, and error-checked*** delivery of a stream of octets between applications running on hosts communicating over an IP network.
+
+## Features
+
+1. Optimized for ***Real-Time Strategy Game***.
+1. Compatible with [skywind3000's](https://github.com/skywind3000) C version with modifications.
+1. ***Cache friendly*** and ***Memory optimized*** design in golang.
+1. Compatible with [net.Conn](https://golang.org/pkg/net/#Conn) and [net.Listener](https://golang.org/pkg/net/#Listener).
+1. [FEC(Forward Error Correction)](https://en.wikipedia.org/wiki/Forward_error_correction) Support with [Reed-Solomon Codes](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction)
+1. Packet level encryption support with [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard), [TEA](https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm), [3DES](https://en.wikipedia.org/wiki/Triple_DES), [Blowfish](https://en.wikipedia.org/wiki/Blowfish_(cipher)), [Cast5](https://en.wikipedia.org/wiki/CAST-128), [Salsa20]( https://en.wikipedia.org/wiki/Salsa20), etc. in [CFB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Feedback_.28CFB.29) mode.
+
+## Conventions
+
+Control messages like SYN/FIN/RST in TCP ***are not defined*** in KCP, you need some ***keepalive mechanims*** in the application-level. a real world example is to use some ***multiplexing*** protocol over session, such as [smux](https://github.com/xtaci/smux), see [kcptun](https://github.com/xtaci/kcptun) for example.
+
+## Documentation
+
+For complete documentation, see the associated [Godoc](https://godoc.org/github.com/xtaci/kcp-go).
+
+## Specification
+
+# <img src="frame.png" alt="Frame Format" height="160px" />
+
+## Usage
+
+Client: [full demo](https://github.com/xtaci/kcptun/blob/master/client/main.go#L231)
+```go
+kcpconn, err := kcp.DialWithOptions("192.168.0.1:10000", nil, 10, 3)
+```
+Server: [full demo](https://github.com/xtaci/kcptun/blob/master/server/main.go#L235)
+```go
+lis, err := kcp.ListenWithOptions(":10000", nil, 10, 3)
+```
+
+## Performance
+```
+ 型号名称: MacBook Pro
+ 型号标识符: MacBookPro12,1
+ 处理器名称: Intel Core i5
+ 处理器速度: 2.7 GHz
+ 处理器数目: 1
+ 核总数: 2
+ L2 缓存(每个核): 256 KB
+ L3 缓存: 3 MB
+ 内存: 8 GB
+```
+```
+$ go test -run Speed
+new client 127.0.0.1:61165
+total recv: 16777216
+time for 16MB rtt with encryption 570.41176ms
+&{BytesSent:33554432 BytesReceived:33554432 MaxConn:2 ActiveOpens:1 PassiveOpens:1 CurrEstab:1 InErrs:0 InCsumErrors:0 InSegs:42577 OutSegs:42641 OutBytes:48111336 RetransSegs:92 FastRetransSegs:92 LostSegs:0 RepeatSegs:0 FECRecovered:1 FECErrs:0 FECSegs:8514}
+PASS
+ok github.com/xtaci/kcp-go 0.600s
+```
+
+## Links
+
+1. https://github.com/xtaci/libkcp -- Official client library for iOS/Android(C++11)
+2. https://github.com/skywind3000/kcp -- A Fast and Reliable ARQ Protocol
+3. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go
+
+## Status
+
+Production Ready
+
+## Donation
+
+![donate](donate.png)
+
+All donations on this project will be used to support the development of [gonet/2](http://gonet2.github.io/).
diff --git a/vendor/github.com/xtaci/kcp-go/crypt.go b/vendor/github.com/xtaci/kcp-go/crypt.go
new file mode 100644
index 0000000..2e456b8
--- /dev/null
+++ b/vendor/github.com/xtaci/kcp-go/crypt.go
@@ -0,0 +1,263 @@
+package kcp
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/sha1"
+
+ "golang.org/x/crypto/blowfish"
+ "golang.org/x/crypto/cast5"
+ "golang.org/x/crypto/pbkdf2"
+ "golang.org/x/crypto/salsa20"
+ "golang.org/x/crypto/tea"
+ "golang.org/x/crypto/twofish"
+ "golang.org/x/crypto/xtea"
+)
+
+var (
+ initialVector = []byte{167, 115, 79, 156, 18, 172, 27, 1, 164, 21, 242, 193, 252, 120, 230, 107}
+ saltxor = `sH3CIVoF#rWLtJo6`
+)
+
+// BlockCrypt defines encryption/decryption methods for a given byte slice.
+// Notes on implementing: the data to be encrypted contains a builtin
+// nonce at the first 16 bytes
+type BlockCrypt interface {
+ // Encrypt encrypts the whole block in src into dst.
+ // Dst and src may point at the same memory.
+ Encrypt(dst, src []byte)
+
+ // Decrypt decrypts the whole block in src into dst.
+ // Dst and src may point at the same memory.
+ Decrypt(dst, src []byte)
+}
+
+type salsa20BlockCrypt struct {
+ key [32]byte
+}
+
+// NewSalsa20BlockCrypt https://en.wikipedia.org/wiki/Salsa20
+func NewSalsa20BlockCrypt(key []byte) (BlockCrypt, error) {
+ c := new(salsa20BlockCrypt)
+ copy(c.key[:], key)
+ return c, nil
+}
+
+func (c *salsa20BlockCrypt) Encrypt(dst, src []byte) {
+ salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key)
+ copy(dst[:8], src[:8])
+}
+func (c *salsa20BlockCrypt) Decrypt(dst, src []byte) {
+ salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key)
+ copy(dst[:8], src[:8])
+}
+
+type twofishBlockCrypt struct {
+ encbuf []byte
+ decbuf []byte
+ block cipher.Block
+}
+
+// NewTwofishBlockCrypt https://en.wikipedia.org/wiki/Twofish
+func NewTwofishBlockCrypt(key []byte) (BlockCrypt, error) {
+ c := new(twofishBlockCrypt)
+ block, err := twofish.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ c.block = block
+ c.encbuf = make([]byte, twofish.BlockSize)
+ c.decbuf = make([]byte, 2*twofish.BlockSize)
+ return c, nil
+}
+
+func (c *twofishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
+func (c *twofishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
+
+type tripleDESBlockCrypt struct {
+ encbuf []byte
+ decbuf []byte
+ block cipher.Block
+}
+
+// NewTripleDESBlockCrypt https://en.wikipedia.org/wiki/Triple_DES
+func NewTripleDESBlockCrypt(key []byte) (BlockCrypt, error) {
+ c := new(tripleDESBlockCrypt)
+ block, err := des.NewTripleDESCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ c.block = block
+ c.encbuf = make([]byte, des.BlockSize)
+ c.decbuf = make([]byte, 2*des.BlockSize)
+ return c, nil
+}
+
+func (c *tripleDESBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
+func (c *tripleDESBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
+
+type cast5BlockCrypt struct {
+ encbuf []byte
+ decbuf []byte
+ block cipher.Block
+}
+
+// NewCast5BlockCrypt https://en.wikipedia.org/wiki/CAST-128
+func NewCast5BlockCrypt(key []byte) (BlockCrypt, error) {
+ c := new(cast5BlockCrypt)
+ block, err := cast5.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ c.block = block
+ c.encbuf = make([]byte, cast5.BlockSize)
+ c.decbuf = make([]byte, 2*cast5.BlockSize)
+ return c, nil
+}
+
+func (c *cast5BlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
+func (c *cast5BlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
+
+type blowfishBlockCrypt struct {
+ encbuf []byte
+ decbuf []byte
+ block cipher.Block
+}
+
+// NewBlowfishBlockCrypt https://en.wikipedia.org/wiki/Blowfish_(cipher)
+func NewBlowfishBlockCrypt(key []byte) (BlockCrypt, error) {
+ c := new(blowfishBlockCrypt)
+ block, err := blowfish.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ c.block = block
+ c.encbuf = make([]byte, blowfish.BlockSize)
+ c.decbuf = make([]byte, 2*blowfish.BlockSize)
+ return c, nil
+}
+
+func (c *blowfishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
+func (c *blowfishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
+
+type aesBlockCrypt struct {
+ encbuf []byte
+ decbuf []byte
+ block cipher.Block
+}
+
+// NewAESBlockCrypt https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
+func NewAESBlockCrypt(key []byte) (BlockCrypt, error) {
+ c := new(aesBlockCrypt)
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ c.block = block
+ c.encbuf = make([]byte, aes.BlockSize)
+ c.decbuf = make([]byte, 2*aes.BlockSize)
+ return c, nil
+}
+
+func (c *aesBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
+func (c *aesBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
+
+type teaBlockCrypt struct {
+ encbuf []byte
+ decbuf []byte
+ block cipher.Block
+}
+
+// NewTEABlockCrypt https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
+func NewTEABlockCrypt(key []byte) (BlockCrypt, error) {
+ c := new(teaBlockCrypt)
+ block, err := tea.NewCipherWithRounds(key, 16)
+ if err != nil {
+ return nil, err
+ }
+ c.block = block
+ c.encbuf = make([]byte, tea.BlockSize)
+ c.decbuf = make([]byte, 2*tea.BlockSize)
+ return c, nil
+}
+
+func (c *teaBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
+func (c *teaBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
+
+type xteaBlockCrypt struct {
+ encbuf []byte
+ decbuf []byte
+ block cipher.Block
+}
+
+// NewXTEABlockCrypt https://en.wikipedia.org/wiki/XTEA
+func NewXTEABlockCrypt(key []byte) (BlockCrypt, error) {
+ c := new(xteaBlockCrypt)
+ block, err := xtea.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ c.block = block
+ c.encbuf = make([]byte, xtea.BlockSize)
+ c.decbuf = make([]byte, 2*xtea.BlockSize)
+ return c, nil
+}
+
+func (c *xteaBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
+func (c *xteaBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
+
+type simpleXORBlockCrypt struct {
+ xortbl []byte
+}
+
+// NewSimpleXORBlockCrypt simple xor with key expanding
+func NewSimpleXORBlockCrypt(key []byte) (BlockCrypt, error) {
+ c := new(simpleXORBlockCrypt)
+ c.xortbl = pbkdf2.Key(key, []byte(saltxor), 32, mtuLimit, sha1.New)
+ return c, nil
+}
+
+func (c *simpleXORBlockCrypt) Encrypt(dst, src []byte) { xorBytes(dst, src, c.xortbl) }
+func (c *simpleXORBlockCrypt) Decrypt(dst, src []byte) { xorBytes(dst, src, c.xortbl) }
+
+type noneBlockCrypt struct{}
+
+// NewNoneBlockCrypt does nothing but copying
+func NewNoneBlockCrypt(key []byte) (BlockCrypt, error) {
+ return new(noneBlockCrypt), nil
+}
+
+func (c *noneBlockCrypt) Encrypt(dst, src []byte) { copy(dst, src) }
+func (c *noneBlockCrypt) Decrypt(dst, src []byte) { copy(dst, src) }
+
+// packet encryption with local CFB mode
+func encrypt(block cipher.Block, dst, src, buf []byte) {
+ blocksize := block.BlockSize()
+ tbl := buf[:blocksize]
+ block.Encrypt(tbl, initialVector)
+ n := len(src) / blocksize
+ base := 0
+ for i := 0; i < n; i++ {
+ xorWords(dst[base:], src[base:], tbl)
+ block.Encrypt(tbl, dst[base:])
+ base += blocksize
+ }
+ xorBytes(dst[base:], src[base:], tbl)
+}
+
+func decrypt(block cipher.Block, dst, src, buf []byte) {
+ blocksize := block.BlockSize()
+ tbl := buf[:blocksize]
+ next := buf[blocksize:]
+ block.Encrypt(tbl, initialVector)
+ n := len(src) / blocksize
+ base := 0
+ for i := 0; i < n; i++ {
+ block.Encrypt(next, src[base:])
+ xorWords(dst[base:], src[base:], tbl)
+ tbl, next = next, tbl
+ base += blocksize
+ }
+ xorBytes(dst[base:], src[base:], tbl)
+}
diff --git a/vendor/github.com/xtaci/kcp-go/donate.png b/vendor/github.com/xtaci/kcp-go/donate.png
new file mode 100644
index 0000000..0f353d9
--- /dev/null
+++ b/vendor/github.com/xtaci/kcp-go/donate.png
Binary files differ
diff --git a/vendor/github.com/xtaci/kcp-go/fec.go b/vendor/github.com/xtaci/kcp-go/fec.go
new file mode 100644
index 0000000..fa7f0ec
--- /dev/null
+++ b/vendor/github.com/xtaci/kcp-go/fec.go
@@ -0,0 +1,236 @@
+package kcp
+
+import (
+ "encoding/binary"
+
+ "github.com/klauspost/reedsolomon"
+)
+
+const (
+ fecHeaderSize = 6
+ fecHeaderSizePlus2 = fecHeaderSize + 2 // plus 2B data size
+ typeData = 0xf1
+ typeFEC = 0xf2
+ fecExpire = 30000 // 30s
+)
+
+type (
+ // FEC defines forward error correction for packets
+ FEC struct {
+ rx []fecPacket // ordered receive queue
+ rxlimit int // queue size limit
+ dataShards int
+ parityShards int
+ shardSize int
+ next uint32 // next seqid
+ enc reedsolomon.Encoder
+ shards [][]byte
+ shardsflag []bool
+ paws uint32 // Protect Against Wrapped Sequence numbers
+ lastCheck uint32
+ }
+
+ fecPacket struct {
+ seqid uint32
+ flag uint16
+ data []byte
+ ts uint32
+ }
+)
+
+func newFEC(rxlimit, dataShards, parityShards int) *FEC {
+ if dataShards <= 0 || parityShards <= 0 {
+ return nil
+ }
+ if rxlimit < dataShards+parityShards {
+ return nil
+ }
+
+ fec := new(FEC)
+ fec.rxlimit = rxlimit
+ fec.dataShards = dataShards
+ fec.parityShards = parityShards
+ fec.shardSize = dataShards + parityShards
+ fec.paws = (0xffffffff/uint32(fec.shardSize) - 1) * uint32(fec.shardSize)
+ enc, err := reedsolomon.New(dataShards, parityShards)
+ if err != nil {
+ return nil
+ }
+ fec.enc = enc
+ fec.shards = make([][]byte, fec.shardSize)
+ fec.shardsflag = make([]bool, fec.shardSize)
+ return fec
+}
+
+// decode a fec packet
+func (fec *FEC) decode(data []byte) fecPacket {
+ var pkt fecPacket
+ pkt.seqid = binary.LittleEndian.Uint32(data)
+ pkt.flag = binary.LittleEndian.Uint16(data[4:])
+ pkt.ts = currentMs()
+ // allocate memory & copy
+ buf := xmitBuf.Get().([]byte)[:len(data)-6]
+ copy(buf, data[6:])
+ pkt.data = buf
+ return pkt
+}
+
+func (fec *FEC) markData(data []byte) {
+ binary.LittleEndian.PutUint32(data, fec.next)
+ binary.LittleEndian.PutUint16(data[4:], typeData)
+ fec.next++
+}
+
+func (fec *FEC) markFEC(data []byte) {
+ binary.LittleEndian.PutUint32(data, fec.next)
+ binary.LittleEndian.PutUint16(data[4:], typeFEC)
+ fec.next++
+ if fec.next >= fec.paws { // paws would only occurs in markFEC
+ fec.next = 0
+ }
+}
+
+// input a fec packet
+func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) {
+ // expiration
+ now := currentMs()
+ if now-fec.lastCheck >= fecExpire {
+ var rx []fecPacket
+ for k := range fec.rx {
+ if now-fec.rx[k].ts < fecExpire {
+ rx = append(rx, fec.rx[k])
+ } else {
+ xmitBuf.Put(fec.rx[k].data)
+ }
+ }
+ fec.rx = rx
+ fec.lastCheck = now
+ }
+
+ // insertion
+ n := len(fec.rx) - 1
+ insertIdx := 0
+ for i := n; i >= 0; i-- {
+ if pkt.seqid == fec.rx[i].seqid { // de-duplicate
+ xmitBuf.Put(pkt.data)
+ return nil
+ } else if pkt.seqid > fec.rx[i].seqid { // insertion
+ insertIdx = i + 1
+ break
+ }
+ }
+
+ // insert into ordered rx queue
+ if insertIdx == n+1 {
+ fec.rx = append(fec.rx, pkt)
+ } else {
+ fec.rx = append(fec.rx, fecPacket{})
+ copy(fec.rx[insertIdx+1:], fec.rx[insertIdx:])
+ fec.rx[insertIdx] = pkt
+ }
+
+ // shard range for current packet
+ shardBegin := pkt.seqid - pkt.seqid%uint32(fec.shardSize)
+ shardEnd := shardBegin + uint32(fec.shardSize) - 1
+
+ // max search range in ordered queue for current shard
+ searchBegin := insertIdx - int(pkt.seqid%uint32(fec.shardSize))
+ if searchBegin < 0 {
+ searchBegin = 0
+ }
+ searchEnd := searchBegin + fec.shardSize - 1
+ if searchEnd >= len(fec.rx) {
+ searchEnd = len(fec.rx) - 1
+ }
+
+ if searchEnd > searchBegin && searchEnd-searchBegin+1 >= fec.dataShards {
+ numshard := 0
+ numDataShard := 0
+ first := -1
+ maxlen := 0
+ shards := fec.shards
+ shardsflag := fec.shardsflag
+ for k := range fec.shards {
+ shards[k] = nil
+ shardsflag[k] = false
+ }
+
+ for i := searchBegin; i <= searchEnd; i++ {
+ seqid := fec.rx[i].seqid
+ if seqid > shardEnd {
+ break
+ } else if seqid >= shardBegin {
+ shards[seqid%uint32(fec.shardSize)] = fec.rx[i].data
+ shardsflag[seqid%uint32(fec.shardSize)] = true
+ numshard++
+ if fec.rx[i].flag == typeData {
+ numDataShard++
+ }
+ if numshard == 1 {
+ first = i
+ }
+ if len(fec.rx[i].data) > maxlen {
+ maxlen = len(fec.rx[i].data)
+ }
+ }
+ }
+
+ if numDataShard == fec.dataShards { // no lost
+ for i := first; i < first+numshard; i++ { // free
+ xmitBuf.Put(fec.rx[i].data)
+ }
+ copy(fec.rx[first:], fec.rx[first+numshard:])
+ for i := 0; i < numshard; i++ { // dereference
+ fec.rx[len(fec.rx)-1-i] = fecPacket{}
+ }
+ fec.rx = fec.rx[:len(fec.rx)-numshard]
+ } else if numshard >= fec.dataShards { // recoverable
+ for k := range shards {
+ if shards[k] != nil {
+ dlen := len(shards[k])
+ shards[k] = shards[k][:maxlen]
+ xorBytes(shards[k][dlen:], shards[k][dlen:], shards[k][dlen:])
+ }
+ }
+ if err := fec.enc.Reconstruct(shards); err == nil {
+ for k := range shards[:fec.dataShards] {
+ if !shardsflag[k] {
+ recovered = append(recovered, shards[k])
+ }
+ }
+ }
+
+ for i := first; i < first+numshard; i++ { // free
+ xmitBuf.Put(fec.rx[i].data)
+ }
+ copy(fec.rx[first:], fec.rx[first+numshard:])
+ for i := 0; i < numshard; i++ { // dereference
+ fec.rx[len(fec.rx)-1-i] = fecPacket{}
+ }
+ fec.rx = fec.rx[:len(fec.rx)-numshard]
+ }
+ }
+
+ // keep rxlimit
+ if len(fec.rx) > fec.rxlimit {
+ xmitBuf.Put(fec.rx[0].data) // free
+ fec.rx[0].data = nil
+ fec.rx = fec.rx[1:]
+ }
+ return
+}
+
+func (fec *FEC) calcECC(data [][]byte, offset, maxlen int) (ecc [][]byte) {
+ if len(data) != fec.shardSize {
+ return nil
+ }
+ shards := make([][]byte, fec.shardSize)
+ for k := range shards {
+ shards[k] = data[k][offset:maxlen]
+ }
+
+ if err := fec.enc.Encode(shards); err != nil {
+ return nil
+ }
+ return data[fec.dataShards:]
+}
diff --git a/vendor/github.com/xtaci/kcp-go/frame.png b/vendor/github.com/xtaci/kcp-go/frame.png
new file mode 100644
index 0000000..7952e4a
--- /dev/null
+++ b/vendor/github.com/xtaci/kcp-go/frame.png
Binary files differ
diff --git a/vendor/github.com/xtaci/kcp-go/kcp.go b/vendor/github.com/xtaci/kcp-go/kcp.go
new file mode 100644
index 0000000..eec4143
--- /dev/null
+++ b/vendor/github.com/xtaci/kcp-go/kcp.go
@@ -0,0 +1,978 @@
+// Package kcp - A Fast and Reliable ARQ Protocol
+package kcp
+
+import (
+ "container/heap"
+ "encoding/binary"
+ "sync/atomic"
+)
+
+const (
+ IKCP_RTO_NDL = 30 // no delay min rto
+ IKCP_RTO_MIN = 100 // normal min rto
+ IKCP_RTO_DEF = 200
+ IKCP_RTO_MAX = 60000
+ IKCP_CMD_PUSH = 81 // cmd: push data
+ IKCP_CMD_ACK = 82 // cmd: ack
+ IKCP_CMD_WASK = 83 // cmd: window probe (ask)
+ IKCP_CMD_WINS = 84 // cmd: window size (tell)
+ IKCP_ASK_SEND = 1 // need to send IKCP_CMD_WASK
+ IKCP_ASK_TELL = 2 // need to send IKCP_CMD_WINS
+ IKCP_WND_SND = 32
+ IKCP_WND_RCV = 32
+ IKCP_MTU_DEF = 1400
+ IKCP_ACK_FAST = 3
+ IKCP_INTERVAL = 100
+ IKCP_OVERHEAD = 24
+ IKCP_DEADLINK = 20
+ IKCP_THRESH_INIT = 2
+ IKCP_THRESH_MIN = 2
+ IKCP_PROBE_INIT = 7000 // 7 secs to probe window size
+ IKCP_PROBE_LIMIT = 120000 // up to 120 secs to probe window
+)
+
+// Output is a closure which captures conn and calls conn.Write
+type Output func(buf []byte, size int)
+
+/* encode 8 bits unsigned int */
+func ikcp_encode8u(p []byte, c byte) []byte {
+ p[0] = c
+ return p[1:]
+}
+
+/* decode 8 bits unsigned int */
+func ikcp_decode8u(p []byte, c *byte) []byte {
+ *c = p[0]
+ return p[1:]
+}
+
+/* encode 16 bits unsigned int (lsb) */
+func ikcp_encode16u(p []byte, w uint16) []byte {
+ binary.LittleEndian.PutUint16(p, w)
+ return p[2:]
+}
+
+/* decode 16 bits unsigned int (lsb) */
+func ikcp_decode16u(p []byte, w *uint16) []byte {
+ *w = binary.LittleEndian.Uint16(p)
+ return p[2:]
+}
+
+/* encode 32 bits unsigned int (lsb) */
+func ikcp_encode32u(p []byte, l uint32) []byte {
+ binary.LittleEndian.PutUint32(p, l)
+ return p[4:]
+}
+
+/* decode 32 bits unsigned int (lsb) */
+func ikcp_decode32u(p []byte, l *uint32) []byte {
+ *l = binary.LittleEndian.Uint32(p)
+ return p[4:]
+}
+
+func _imin_(a, b uint32) uint32 {
+ if a <= b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func _imax_(a, b uint32) uint32 {
+ if a >= b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func _ibound_(lower, middle, upper uint32) uint32 {
+ return _imin_(_imax_(lower, middle), upper)
+}
+
+func _itimediff(later, earlier uint32) int32 {
+ return (int32)(later - earlier)
+}
+
+// Segment defines a KCP segment
+type Segment struct {
+ conv uint32
+ cmd uint32
+ frg uint32
+ wnd uint32
+ ts uint32
+ sn uint32
+ una uint32
+ resendts uint32
+ rto uint32
+ fastack uint32
+ xmit uint32
+ data []byte
+}
+
+// encode a segment into buffer
+func (seg *Segment) encode(ptr []byte) []byte {
+ ptr = ikcp_encode32u(ptr, seg.conv)
+ ptr = ikcp_encode8u(ptr, uint8(seg.cmd))
+ ptr = ikcp_encode8u(ptr, uint8(seg.frg))
+ ptr = ikcp_encode16u(ptr, uint16(seg.wnd))
+ ptr = ikcp_encode32u(ptr, seg.ts)
+ ptr = ikcp_encode32u(ptr, seg.sn)
+ ptr = ikcp_encode32u(ptr, seg.una)
+ ptr = ikcp_encode32u(ptr, uint32(len(seg.data)))
+ return ptr
+}
+
+// KCP defines a single KCP connection
+type KCP struct {
+ conv, mtu, mss, state uint32
+ snd_una, snd_nxt, rcv_nxt uint32
+ ssthresh uint32
+ rx_rttval, rx_srtt, rx_rto, rx_minrto uint32
+ snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe uint32
+ current, interval, ts_flush, xmit uint32
+ nodelay, updated uint32
+ ts_probe, probe_wait uint32
+ dead_link, incr uint32
+
+ fastresend int32
+ nocwnd, stream int32
+
+ snd_queue []Segment
+ rcv_queue []Segment
+ snd_buf []Segment
+ rcv_buf []Segment
+
+ acklist ackList
+
+ buffer []byte
+ output Output
+}
+
+type ackItem struct {
+ sn uint32
+ ts uint32
+}
+
+type ackList []ackItem
+
+func (l ackList) Len() int { return len(l) }
+func (l ackList) Less(i, j int) bool { return l[i].sn < l[j].sn }
+func (l ackList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+func (l *ackList) Push(x interface{}) { *l = append(*l, x.(ackItem)) }
+func (l *ackList) Pop() interface{} {
+ old := *l
+ n := len(old)
+ x := old[n-1]
+ *l = old[0 : n-1]
+ return x
+}
+
+// NewKCP create a new kcp control object, 'conv' must equal in two endpoint
+// from the same connection.
+func NewKCP(conv uint32, output Output) *KCP {
+ kcp := new(KCP)
+ kcp.conv = conv
+ kcp.snd_wnd = IKCP_WND_SND
+ kcp.rcv_wnd = IKCP_WND_RCV
+ kcp.rmt_wnd = IKCP_WND_RCV
+ kcp.mtu = IKCP_MTU_DEF
+ kcp.mss = kcp.mtu - IKCP_OVERHEAD
+ kcp.buffer = make([]byte, (kcp.mtu+IKCP_OVERHEAD)*3)
+ kcp.rx_rto = IKCP_RTO_DEF
+ kcp.rx_minrto = IKCP_RTO_MIN
+ kcp.interval = IKCP_INTERVAL
+ kcp.ts_flush = IKCP_INTERVAL
+ kcp.ssthresh = IKCP_THRESH_INIT
+ kcp.dead_link = IKCP_DEADLINK
+ kcp.output = output
+ return kcp
+}
+
+// newSegment creates a KCP segment
+func (kcp *KCP) newSegment(size int) *Segment {
+ seg := new(Segment)
+ seg.data = xmitBuf.Get().([]byte)[:size]
+ return seg
+}
+
+// delSegment recycles a KCP segment
+func (kcp *KCP) delSegment(seg *Segment) {
+ xmitBuf.Put(seg.data)
+}
+
+// PeekSize checks the size of next message in the recv queue
+func (kcp *KCP) PeekSize() (length int) {
+ if len(kcp.rcv_queue) == 0 {
+ return -1
+ }
+
+ seg := &kcp.rcv_queue[0]
+ if seg.frg == 0 {
+ return len(seg.data)
+ }
+
+ if len(kcp.rcv_queue) < int(seg.frg+1) {
+ return -1
+ }
+
+ for k := range kcp.rcv_queue {
+ seg := &kcp.rcv_queue[k]
+ length += len(seg.data)
+ if seg.frg == 0 {
+ break
+ }
+ }
+ return
+}
+
+// Recv is user/upper level recv: returns size, returns below zero for EAGAIN
+func (kcp *KCP) Recv(buffer []byte) (n int) {
+ if len(kcp.rcv_queue) == 0 {
+ return -1
+ }
+
+ peeksize := kcp.PeekSize()
+ if peeksize < 0 {
+ return -2
+ }
+
+ if peeksize > len(buffer) {
+ return -3
+ }
+
+ var fast_recover bool
+ if len(kcp.rcv_queue) >= int(kcp.rcv_wnd) {
+ fast_recover = true
+ }
+
+ // merge fragment
+ count := 0
+ for k := range kcp.rcv_queue {
+ seg := &kcp.rcv_queue[k]
+ copy(buffer, seg.data)
+ buffer = buffer[len(seg.data):]
+ n += len(seg.data)
+ count++
+ kcp.delSegment(seg)
+ if seg.frg == 0 {
+ break
+ }
+ }
+ kcp.rcv_queue = kcp.rcv_queue[count:]
+
+ // move available data from rcv_buf -> rcv_queue
+ count = 0
+ for k := range kcp.rcv_buf {
+ seg := &kcp.rcv_buf[k]
+ if seg.sn == kcp.rcv_nxt && len(kcp.rcv_queue) < int(kcp.rcv_wnd) {
+ kcp.rcv_nxt++
+ count++
+ } else {
+ break
+ }
+ }
+ kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...)
+ kcp.rcv_buf = kcp.rcv_buf[count:]
+
+ // fast recover
+ if len(kcp.rcv_queue) < int(kcp.rcv_wnd) && fast_recover {
+ // ready to send back IKCP_CMD_WINS in ikcp_flush
+ // tell remote my window size
+ kcp.probe |= IKCP_ASK_TELL
+ }
+ return
+}
+
+// Send is user/upper level send, returns below zero for error
+func (kcp *KCP) Send(buffer []byte) int {
+ var count int
+ if len(buffer) == 0 {
+ return -1
+ }
+
+ // append to previous segment in streaming mode (if possible)
+ if kcp.stream != 0 {
+ n := len(kcp.snd_queue)
+ if n > 0 {
+ old := &kcp.snd_queue[n-1]
+ if len(old.data) < int(kcp.mss) {
+ capacity := int(kcp.mss) - len(old.data)
+ extend := capacity
+ if len(buffer) < capacity {
+ extend = len(buffer)
+ }
+ seg := kcp.newSegment(len(old.data) + extend)
+ seg.frg = 0