From 1e709ceababe54dc0254683304147359b9d59146 Mon Sep 17 00:00:00 2001 From: "rui.zheng" Date: Sat, 11 Feb 2017 20:45:40 +0800 Subject: [PATCH] update kcp vendor --- .../github.com/codahale/chacha20/LICENSE | 21 -- .../github.com/codahale/chacha20/README.md | 8 - .../github.com/codahale/chacha20/chacha20.go | 235 ------------ .../github.com/codahale/chacha20/core_ref.go | 166 --------- .../vendor/github.com/klauspost/crc32/LICENSE | 28 -- .../github.com/klauspost/crc32/README.md | 87 ----- .../github.com/klauspost/crc32/crc32.go | 207 ----------- .../github.com/klauspost/crc32/crc32_amd64.go | 230 ------------ .../github.com/klauspost/crc32/crc32_amd64.s | 319 ---------------- .../klauspost/crc32/crc32_amd64p32.go | 43 --- .../klauspost/crc32/crc32_amd64p32.s | 67 ---- .../klauspost/crc32/crc32_generic.go | 89 ----- .../klauspost/crc32/crc32_otherarch.go | 15 - .../github.com/klauspost/crc32/crc32_s390x.go | 91 ----- .../github.com/klauspost/crc32/crc32_s390x.s | 249 ------------- .../vendor/gopkg.in/xtaci/kcp-go.v2/README.md | 25 +- .../vendor/gopkg.in/xtaci/kcp-go.v2/crypt.go | 150 +++----- .../vendor/gopkg.in/xtaci/kcp-go.v2/fec.go | 31 +- .../vendor/gopkg.in/xtaci/kcp-go.v2/frame.png | Bin 8179 -> 36006 bytes .../gopkg.in/xtaci/kcp-go.v2/kcp-go.png | Bin 0 -> 9153 bytes .../vendor/gopkg.in/xtaci/kcp-go.v2/kcp.go | 177 ++++----- .../vendor/gopkg.in/xtaci/kcp-go.v2/sess.go | 346 ++++++++++-------- .../vendor/gopkg.in/xtaci/kcp-go.v2/snmp.go | 110 +++++- .../vendor/gopkg.in/xtaci/kcp-go.v2/xor.go | 38 +- .../vendor/gopkg.in/xtaci/smux.v1/README.md | 4 +- .../vendor/gopkg.in/xtaci/smux.v1/session.go | 111 ++++-- .../vendor/gopkg.in/xtaci/smux.v1/stream.go | 144 ++++++-- cmd/gost/vendor/vendor.json | 24 +- 28 files changed, 703 insertions(+), 2312 deletions(-) delete mode 100644 cmd/gost/vendor/github.com/codahale/chacha20/LICENSE delete mode 100644 cmd/gost/vendor/github.com/codahale/chacha20/README.md delete mode 100644 cmd/gost/vendor/github.com/codahale/chacha20/chacha20.go delete mode 100644 cmd/gost/vendor/github.com/codahale/chacha20/core_ref.go delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/LICENSE delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/README.md delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/crc32.go delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.go delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.s delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.go delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.s delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/crc32_generic.go delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/crc32_otherarch.go delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.go delete mode 100644 cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.s create mode 100644 cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp-go.png diff --git a/cmd/gost/vendor/github.com/codahale/chacha20/LICENSE b/cmd/gost/vendor/github.com/codahale/chacha20/LICENSE deleted file mode 100644 index f9835c2..0000000 --- a/cmd/gost/vendor/github.com/codahale/chacha20/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Coda Hale - -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/cmd/gost/vendor/github.com/codahale/chacha20/README.md b/cmd/gost/vendor/github.com/codahale/chacha20/README.md deleted file mode 100644 index e0cc2ec..0000000 --- a/cmd/gost/vendor/github.com/codahale/chacha20/README.md +++ /dev/null @@ -1,8 +0,0 @@ -chacha20 -======== - -[![Build Status](https://travis-ci.org/codahale/chacha20.png?branch=master)](https://travis-ci.org/codahale/chacha20) - -A pure Go implementation of the ChaCha20 stream cipher. - -For documentation, check [godoc](http://godoc.org/github.com/codahale/chacha20). diff --git a/cmd/gost/vendor/github.com/codahale/chacha20/chacha20.go b/cmd/gost/vendor/github.com/codahale/chacha20/chacha20.go deleted file mode 100644 index ae671bc..0000000 --- a/cmd/gost/vendor/github.com/codahale/chacha20/chacha20.go +++ /dev/null @@ -1,235 +0,0 @@ -// Package chacha20 provides a pure Go implementation of ChaCha20, a fast, -// secure stream cipher. -// -// From Bernstein, Daniel J. "ChaCha, a variant of Salsa20." Workshop Record of -// SASC. 2008. (http://cr.yp.to/chacha/chacha-20080128.pdf): -// -// ChaCha8 is a 256-bit stream cipher based on the 8-round cipher Salsa20/8. -// The changes from Salsa20/8 to ChaCha8 are designed to improve diffusion per -// round, conjecturally increasing resistance to cryptanalysis, while -// preserving -- and often improving -- time per round. ChaCha12 and ChaCha20 -// are analogous modifications of the 12-round and 20-round ciphers Salsa20/12 -// and Salsa20/20. This paper presents the ChaCha family and explains the -// differences between Salsa20 and ChaCha. -// -// For more information, see http://cr.yp.to/chacha.html -package chacha20 - -import ( - "crypto/cipher" - "encoding/binary" - "errors" - "unsafe" -) - -const ( - // KeySize is the length of ChaCha20 keys, in bytes. - KeySize = 32 - // NonceSize is the length of ChaCha20 nonces, in bytes. - NonceSize = 8 - // XNonceSize is the length of XChaCha20 nonces, in bytes. - XNonceSize = 24 -) - -var ( - // ErrInvalidKey is returned when the provided key is not 256 bits long. - ErrInvalidKey = errors.New("invalid key length (must be 256 bits)") - // ErrInvalidNonce is returned when the provided nonce is not 64 bits long. - ErrInvalidNonce = errors.New("invalid nonce length (must be 64 bits)") - // ErrInvalidXNonce is returned when the provided nonce is not 192 bits - // long. - ErrInvalidXNonce = errors.New("invalid nonce length (must be 192 bits)") - // ErrInvalidRounds is returned when the provided rounds is not - // 8, 12, or 20. - ErrInvalidRounds = errors.New("invalid rounds number (must be 8, 12, or 20)") -) - -// New creates and returns a new cipher.Stream. The key argument must be 256 -// bits long, and the nonce argument must be 64 bits long. The nonce must be -// randomly generated or used only once. This Stream instance must not be used -// to encrypt more than 2^70 bytes (~1 zettabyte). -func New(key []byte, nonce []byte) (cipher.Stream, error) { - return NewWithRounds(key, nonce, 20) -} - -// NewWithRounds creates and returns a new cipher.Stream just like New but -// the rounds number of 8, 12, or 20 can be specified. -func NewWithRounds(key []byte, nonce []byte, rounds uint8) (cipher.Stream, error) { - if len(key) != KeySize { - return nil, ErrInvalidKey - } - - if len(nonce) != NonceSize { - return nil, ErrInvalidNonce - } - - if (rounds != 8) && (rounds != 12) && (rounds != 20) { - return nil, ErrInvalidRounds - } - - s := new(stream) - s.init(key, nonce, rounds) - s.advance() - - return s, nil -} - -// NewXChaCha creates and returns a new cipher.Stream. The key argument must be -// 256 bits long, and the nonce argument must be 192 bits long. The nonce must -// be randomly generated or only used once. This Stream instance must not be -// used to encrypt more than 2^70 bytes (~1 zetta byte). -func NewXChaCha(key []byte, nonce []byte) (cipher.Stream, error) { - return NewXChaChaWithRounds(key, nonce, 20) -} - -// NewXChaChaWithRounds creates and returns a new cipher.Stream just like -// NewXChaCha but the rounds number of 8, 12, or 20 can be specified. -func NewXChaChaWithRounds(key []byte, nonce []byte, rounds uint8) (cipher.Stream, error) { - if len(key) != KeySize { - return nil, ErrInvalidKey - } - - if len(nonce) != XNonceSize { - return nil, ErrInvalidXNonce - } - - if (rounds != 8) && (rounds != 12) && (rounds != 20) { - return nil, ErrInvalidRounds - } - - s := new(stream) - s.init(key, nonce, rounds) - - // Call HChaCha to derive the subkey using the key and the first 16 bytes - // of the nonce, and re-initialize the state using the subkey and the - // remaining nonce. - blockArr := (*[stateSize]uint32)(unsafe.Pointer(&s.block)) - core(&s.state, blockArr, s.rounds, true) - copy(s.state[4:8], blockArr[0:4]) - copy(s.state[8:12], blockArr[12:16]) - s.state[12] = 0 - s.state[13] = 0 - s.state[14] = binary.LittleEndian.Uint32(nonce[16:]) - s.state[15] = binary.LittleEndian.Uint32(nonce[20:]) - - s.advance() - - return s, nil -} - -type stream struct { - state [stateSize]uint32 // the state as an array of 16 32-bit words - block [blockSize]byte // the keystream as an array of 64 bytes - offset int // the offset of used bytes in block - rounds uint8 -} - -func (s *stream) XORKeyStream(dst, src []byte) { - // Stride over the input in 64-byte blocks, minus the amount of keystream - // previously used. This will produce best results when processing blocks - // of a size evenly divisible by 64. - i := 0 - max := len(src) - for i < max { - gap := blockSize - s.offset - - limit := i + gap - if limit > max { - limit = max - } - - o := s.offset - for j := i; j < limit; j++ { - dst[j] = src[j] ^ s.block[o] - o++ - } - - i += gap - s.offset = o - - if o == blockSize { - s.advance() - } - } -} - -func (s *stream) init(key []byte, nonce []byte, rounds uint8) { - // the magic constants for 256-bit keys - s.state[0] = 0x61707865 - s.state[1] = 0x3320646e - s.state[2] = 0x79622d32 - s.state[3] = 0x6b206574 - - s.state[4] = binary.LittleEndian.Uint32(key[0:]) - s.state[5] = binary.LittleEndian.Uint32(key[4:]) - s.state[6] = binary.LittleEndian.Uint32(key[8:]) - s.state[7] = binary.LittleEndian.Uint32(key[12:]) - s.state[8] = binary.LittleEndian.Uint32(key[16:]) - s.state[9] = binary.LittleEndian.Uint32(key[20:]) - s.state[10] = binary.LittleEndian.Uint32(key[24:]) - s.state[11] = binary.LittleEndian.Uint32(key[28:]) - - switch len(nonce) { - case NonceSize: - // ChaCha20 uses 8 byte nonces. - s.state[12] = 0 - s.state[13] = 0 - s.state[14] = binary.LittleEndian.Uint32(nonce[0:]) - s.state[15] = binary.LittleEndian.Uint32(nonce[4:]) - case XNonceSize: - // XChaCha20 derives the subkey via HChaCha initialized - // with the first 16 bytes of the nonce. - s.state[12] = binary.LittleEndian.Uint32(nonce[0:]) - s.state[13] = binary.LittleEndian.Uint32(nonce[4:]) - s.state[14] = binary.LittleEndian.Uint32(nonce[8:]) - s.state[15] = binary.LittleEndian.Uint32(nonce[12:]) - default: - // Never happens, both ctors validate the nonce length. - panic("invalid nonce size") - } - - s.rounds = rounds -} - -// BUG(codahale): Totally untested on big-endian CPUs. Would very much -// appreciate someone with an ARM device giving this a swing. - -// advances the keystream -func (s *stream) advance() { - core(&s.state, (*[stateSize]uint32)(unsafe.Pointer(&s.block)), s.rounds, false) - - if bigEndian { - j := blockSize - 1 - for i := 0; i < blockSize/2; i++ { - s.block[j], s.block[i] = s.block[i], s.block[j] - j-- - } - } - - s.offset = 0 - i := s.state[12] + 1 - s.state[12] = i - if i == 0 { - s.state[13]++ - } -} - -const ( - wordSize = 4 // the size of ChaCha20's words - stateSize = 16 // the size of ChaCha20's state, in words - blockSize = stateSize * wordSize // the size of ChaCha20's block, in bytes -) - -var ( - bigEndian bool // whether or not we're running on a bigEndian CPU -) - -// Do some up-front bookkeeping on what sort of CPU we're using. ChaCha20 treats -// its state as a little-endian byte array when it comes to generating the -// keystream, which allows for a zero-copy approach to the core transform. On -// big-endian architectures, we have to take a hit to reverse the bytes. -func init() { - x := uint32(0x04030201) - y := [4]byte{0x1, 0x2, 0x3, 0x4} - bigEndian = *(*[4]byte)(unsafe.Pointer(&x)) != y -} diff --git a/cmd/gost/vendor/github.com/codahale/chacha20/core_ref.go b/cmd/gost/vendor/github.com/codahale/chacha20/core_ref.go deleted file mode 100644 index 84f5e6c..0000000 --- a/cmd/gost/vendor/github.com/codahale/chacha20/core_ref.go +++ /dev/null @@ -1,166 +0,0 @@ -// The ChaCha20 core transform. -// An unrolled and inlined implementation in pure Go. - -package chacha20 - -func core(input, output *[stateSize]uint32, rounds uint8, hchacha bool) { - var ( - x00 = input[0] - x01 = input[1] - x02 = input[2] - x03 = input[3] - x04 = input[4] - x05 = input[5] - x06 = input[6] - x07 = input[7] - x08 = input[8] - x09 = input[9] - x10 = input[10] - x11 = input[11] - x12 = input[12] - x13 = input[13] - x14 = input[14] - x15 = input[15] - ) - - var x uint32 - - // Unrolling all 20 rounds kills performance on modern Intel processors - // (Tested on a i5 Haswell, likely applies to Sandy Bridge+), due to uop - // cache thrashing. The straight forward 2 rounds per loop implementation - // of this has double the performance of the fully unrolled version. - for i := uint8(0); i < rounds; i += 2 { - x00 += x04 - x = x12 ^ x00 - x12 = (x << 16) | (x >> 16) - x08 += x12 - x = x04 ^ x08 - x04 = (x << 12) | (x >> 20) - x00 += x04 - x = x12 ^ x00 - x12 = (x << 8) | (x >> 24) - x08 += x12 - x = x04 ^ x08 - x04 = (x << 7) | (x >> 25) - x01 += x05 - x = x13 ^ x01 - x13 = (x << 16) | (x >> 16) - x09 += x13 - x = x05 ^ x09 - x05 = (x << 12) | (x >> 20) - x01 += x05 - x = x13 ^ x01 - x13 = (x << 8) | (x >> 24) - x09 += x13 - x = x05 ^ x09 - x05 = (x << 7) | (x >> 25) - x02 += x06 - x = x14 ^ x02 - x14 = (x << 16) | (x >> 16) - x10 += x14 - x = x06 ^ x10 - x06 = (x << 12) | (x >> 20) - x02 += x06 - x = x14 ^ x02 - x14 = (x << 8) | (x >> 24) - x10 += x14 - x = x06 ^ x10 - x06 = (x << 7) | (x >> 25) - x03 += x07 - x = x15 ^ x03 - x15 = (x << 16) | (x >> 16) - x11 += x15 - x = x07 ^ x11 - x07 = (x << 12) | (x >> 20) - x03 += x07 - x = x15 ^ x03 - x15 = (x << 8) | (x >> 24) - x11 += x15 - x = x07 ^ x11 - x07 = (x << 7) | (x >> 25) - x00 += x05 - x = x15 ^ x00 - x15 = (x << 16) | (x >> 16) - x10 += x15 - x = x05 ^ x10 - x05 = (x << 12) | (x >> 20) - x00 += x05 - x = x15 ^ x00 - x15 = (x << 8) | (x >> 24) - x10 += x15 - x = x05 ^ x10 - x05 = (x << 7) | (x >> 25) - x01 += x06 - x = x12 ^ x01 - x12 = (x << 16) | (x >> 16) - x11 += x12 - x = x06 ^ x11 - x06 = (x << 12) | (x >> 20) - x01 += x06 - x = x12 ^ x01 - x12 = (x << 8) | (x >> 24) - x11 += x12 - x = x06 ^ x11 - x06 = (x << 7) | (x >> 25) - x02 += x07 - x = x13 ^ x02 - x13 = (x << 16) | (x >> 16) - x08 += x13 - x = x07 ^ x08 - x07 = (x << 12) | (x >> 20) - x02 += x07 - x = x13 ^ x02 - x13 = (x << 8) | (x >> 24) - x08 += x13 - x = x07 ^ x08 - x07 = (x << 7) | (x >> 25) - x03 += x04 - x = x14 ^ x03 - x14 = (x << 16) | (x >> 16) - x09 += x14 - x = x04 ^ x09 - x04 = (x << 12) | (x >> 20) - x03 += x04 - x = x14 ^ x03 - x14 = (x << 8) | (x >> 24) - x09 += x14 - x = x04 ^ x09 - x04 = (x << 7) | (x >> 25) - } - - if !hchacha { - output[0] = x00 + input[0] - output[1] = x01 + input[1] - output[2] = x02 + input[2] - output[3] = x03 + input[3] - output[4] = x04 + input[4] - output[5] = x05 + input[5] - output[6] = x06 + input[6] - output[7] = x07 + input[7] - output[8] = x08 + input[8] - output[9] = x09 + input[9] - output[10] = x10 + input[10] - output[11] = x11 + input[11] - output[12] = x12 + input[12] - output[13] = x13 + input[13] - output[14] = x14 + input[14] - output[15] = x15 + input[15] - } else { - output[0] = x00 - output[1] = x01 - output[2] = x02 - output[3] = x03 - output[4] = x04 - output[5] = x05 - output[6] = x06 - output[7] = x07 - output[8] = x08 - output[9] = x09 - output[10] = x10 - output[11] = x11 - output[12] = x12 - output[13] = x13 - output[14] = x14 - output[15] = x15 - } -} diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/LICENSE b/cmd/gost/vendor/github.com/klauspost/crc32/LICENSE deleted file mode 100644 index 4fd5963..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. -Copyright (c) 2015 Klaus Post - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/README.md b/cmd/gost/vendor/github.com/klauspost/crc32/README.md deleted file mode 100644 index 029625d..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# crc32 -CRC32 hash with x64 optimizations - -This package is a drop-in replacement for the standard library `hash/crc32` package, that features SSE 4.2 optimizations on x64 platforms, for a 10x speedup. - -[![Build Status](https://travis-ci.org/klauspost/crc32.svg?branch=master)](https://travis-ci.org/klauspost/crc32) - -# usage - -Install using `go get github.com/klauspost/crc32`. This library is based on Go 1.5 code and requires Go 1.3 or newer. - -Replace `import "hash/crc32"` with `import "github.com/klauspost/crc32"` and you are good to go. - -# changes -* Oct 20, 2016: Changes have been merged to upstream Go. Package updated to match. -* Dec 4, 2015: Uses the "slice-by-8" trick more extensively, which gives a 1.5 to 2.5x speedup if assembler is unavailable. - - -# performance - -For *Go 1.7* performance is equivalent to the standard library. So if you use this package for Go 1.7 you can switch back. - - -For IEEE tables (the most common), there is approximately a factor 10 speedup with "CLMUL" (Carryless multiplication) instruction: -``` -benchmark old ns/op new ns/op delta -BenchmarkCrc32KB 99955 10258 -89.74% - -benchmark old MB/s new MB/s speedup -BenchmarkCrc32KB 327.83 3194.20 9.74x -``` - -For other tables and "CLMUL" capable machines the performance is the same as the standard library. - -Here are some detailed benchmarks, comparing to go 1.5 standard library with and without assembler enabled. - -``` -Std: Standard Go 1.5 library -Crc: Indicates IEEE type CRC. -40B: Size of each slice encoded. -NoAsm: Assembler was disabled (ie. not an AMD64 or SSE 4.2+ capable machine). -Castagnoli: Castagnoli CRC type. - -BenchmarkStdCrc40B-4 10000000 158 ns/op 252.88 MB/s -BenchmarkCrc40BNoAsm-4 20000000 105 ns/op 377.38 MB/s (slice8) -BenchmarkCrc40B-4 20000000 105 ns/op 378.77 MB/s (slice8) - -BenchmarkStdCrc1KB-4 500000 3604 ns/op 284.10 MB/s -BenchmarkCrc1KBNoAsm-4 1000000 1463 ns/op 699.79 MB/s (slice8) -BenchmarkCrc1KB-4 3000000 396 ns/op 2583.69 MB/s (asm) - -BenchmarkStdCrc8KB-4 200000 11417 ns/op 717.48 MB/s (slice8) -BenchmarkCrc8KBNoAsm-4 200000 11317 ns/op 723.85 MB/s (slice8) -BenchmarkCrc8KB-4 500000 2919 ns/op 2805.73 MB/s (asm) - -BenchmarkStdCrc32KB-4 30000 45749 ns/op 716.24 MB/s (slice8) -BenchmarkCrc32KBNoAsm-4 30000 45109 ns/op 726.42 MB/s (slice8) -BenchmarkCrc32KB-4 100000 11497 ns/op 2850.09 MB/s (asm) - -BenchmarkStdNoAsmCastagnol40B-4 10000000 161 ns/op 246.94 MB/s -BenchmarkStdCastagnoli40B-4 50000000 28.4 ns/op 1410.69 MB/s (asm) -BenchmarkCastagnoli40BNoAsm-4 20000000 100 ns/op 398.01 MB/s (slice8) -BenchmarkCastagnoli40B-4 50000000 28.2 ns/op 1419.54 MB/s (asm) - -BenchmarkStdNoAsmCastagnoli1KB-4 500000 3622 ns/op 282.67 MB/s -BenchmarkStdCastagnoli1KB-4 10000000 144 ns/op 7099.78 MB/s (asm) -BenchmarkCastagnoli1KBNoAsm-4 1000000 1475 ns/op 694.14 MB/s (slice8) -BenchmarkCastagnoli1KB-4 10000000 146 ns/op 6993.35 MB/s (asm) - -BenchmarkStdNoAsmCastagnoli8KB-4 50000 28781 ns/op 284.63 MB/s -BenchmarkStdCastagnoli8KB-4 1000000 1029 ns/op 7957.89 MB/s (asm) -BenchmarkCastagnoli8KBNoAsm-4 200000 11410 ns/op 717.94 MB/s (slice8) -BenchmarkCastagnoli8KB-4 1000000 1000 ns/op 8188.71 MB/s (asm) - -BenchmarkStdNoAsmCastagnoli32KB-4 10000 115426 ns/op 283.89 MB/s -BenchmarkStdCastagnoli32KB-4 300000 4065 ns/op 8059.13 MB/s (asm) -BenchmarkCastagnoli32KBNoAsm-4 30000 45171 ns/op 725.41 MB/s (slice8) -BenchmarkCastagnoli32KB-4 500000 4077 ns/op 8035.89 MB/s (asm) -``` - -The IEEE assembler optimizations has been submitted and will be part of the Go 1.6 standard library. - -However, the improved use of slice-by-8 has not, but will probably be submitted for Go 1.7. - -# license - -Standard Go license. Changes are Copyright (c) 2015 Klaus Post under same conditions. diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/crc32.go b/cmd/gost/vendor/github.com/klauspost/crc32/crc32.go deleted file mode 100644 index 8aa91b1..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/crc32.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32, -// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for -// information. -// -// Polynomials are represented in LSB-first form also known as reversed representation. -// -// See http://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials -// for information. -package crc32 - -import ( - "hash" - "sync" -) - -// The size of a CRC-32 checksum in bytes. -const Size = 4 - -// Predefined polynomials. -const ( - // IEEE is by far and away the most common CRC-32 polynomial. - // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ... - IEEE = 0xedb88320 - - // Castagnoli's polynomial, used in iSCSI. - // Has better error detection characteristics than IEEE. - // http://dx.doi.org/10.1109/26.231911 - Castagnoli = 0x82f63b78 - - // Koopman's polynomial. - // Also has better error detection characteristics than IEEE. - // http://dx.doi.org/10.1109/DSN.2002.1028931 - Koopman = 0xeb31d82e -) - -// Table is a 256-word table representing the polynomial for efficient processing. -type Table [256]uint32 - -// This file makes use of functions implemented in architecture-specific files. -// The interface that they implement is as follows: -// -// // archAvailableIEEE reports whether an architecture-specific CRC32-IEEE -// // algorithm is available. -// archAvailableIEEE() bool -// -// // archInitIEEE initializes the architecture-specific CRC3-IEEE algorithm. -// // It can only be called if archAvailableIEEE() returns true. -// archInitIEEE() -// -// // archUpdateIEEE updates the given CRC32-IEEE. It can only be called if -// // archInitIEEE() was previously called. -// archUpdateIEEE(crc uint32, p []byte) uint32 -// -// // archAvailableCastagnoli reports whether an architecture-specific -// // CRC32-C algorithm is available. -// archAvailableCastagnoli() bool -// -// // archInitCastagnoli initializes the architecture-specific CRC32-C -// // algorithm. It can only be called if archAvailableCastagnoli() returns -// // true. -// archInitCastagnoli() -// -// // archUpdateCastagnoli updates the given CRC32-C. It can only be called -// // if archInitCastagnoli() was previously called. -// archUpdateCastagnoli(crc uint32, p []byte) uint32 - -// castagnoliTable points to a lazily initialized Table for the Castagnoli -// polynomial. MakeTable will always return this value when asked to make a -// Castagnoli table so we can compare against it to find when the caller is -// using this polynomial. -var castagnoliTable *Table -var castagnoliTable8 *slicing8Table -var castagnoliArchImpl bool -var updateCastagnoli func(crc uint32, p []byte) uint32 -var castagnoliOnce sync.Once - -func castagnoliInit() { - castagnoliTable = simpleMakeTable(Castagnoli) - castagnoliArchImpl = archAvailableCastagnoli() - - if castagnoliArchImpl { - archInitCastagnoli() - updateCastagnoli = archUpdateCastagnoli - } else { - // Initialize the slicing-by-8 table. - castagnoliTable8 = slicingMakeTable(Castagnoli) - updateCastagnoli = func(crc uint32, p []byte) uint32 { - return slicingUpdate(crc, castagnoliTable8, p) - } - } -} - -// IEEETable is the table for the IEEE polynomial. -var IEEETable = simpleMakeTable(IEEE) - -// ieeeTable8 is the slicing8Table for IEEE -var ieeeTable8 *slicing8Table -var ieeeArchImpl bool -var updateIEEE func(crc uint32, p []byte) uint32 -var ieeeOnce sync.Once - -func ieeeInit() { - ieeeArchImpl = archAvailableIEEE() - - if ieeeArchImpl { - archInitIEEE() - updateIEEE = archUpdateIEEE - } else { - // Initialize the slicing-by-8 table. - ieeeTable8 = slicingMakeTable(IEEE) - updateIEEE = func(crc uint32, p []byte) uint32 { - return slicingUpdate(crc, ieeeTable8, p) - } - } -} - -// MakeTable returns a Table constructed from the specified polynomial. -// The contents of this Table must not be modified. -func MakeTable(poly uint32) *Table { - switch poly { - case IEEE: - ieeeOnce.Do(ieeeInit) - return IEEETable - case Castagnoli: - castagnoliOnce.Do(castagnoliInit) - return castagnoliTable - } - return simpleMakeTable(poly) -} - -// digest represents the partial evaluation of a checksum. -type digest struct { - crc uint32 - tab *Table -} - -// New creates a new hash.Hash32 computing the CRC-32 checksum -// using the polynomial represented by the Table. -// Its Sum method will lay the value out in big-endian byte order. -func New(tab *Table) hash.Hash32 { - if tab == IEEETable { - ieeeOnce.Do(ieeeInit) - } - return &digest{0, tab} -} - -// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum -// using the IEEE polynomial. -// Its Sum method will lay the value out in big-endian byte order. -func NewIEEE() hash.Hash32 { return New(IEEETable) } - -func (d *digest) Size() int { return Size } - -func (d *digest) BlockSize() int { return 1 } - -func (d *digest) Reset() { d.crc = 0 } - -// Update returns the result of adding the bytes in p to the crc. -func Update(crc uint32, tab *Table, p []byte) uint32 { - switch tab { - case castagnoliTable: - return updateCastagnoli(crc, p) - case IEEETable: - // Unfortunately, because IEEETable is exported, IEEE may be used without a - // call to MakeTable. We have to make sure it gets initialized in that case. - ieeeOnce.Do(ieeeInit) - return updateIEEE(crc, p) - default: - return simpleUpdate(crc, tab, p) - } -} - -func (d *digest) Write(p []byte) (n int, err error) { - switch d.tab { - case castagnoliTable: - d.crc = updateCastagnoli(d.crc, p) - case IEEETable: - // We only create digest objects through New() which takes care of - // initialization in this case. - d.crc = updateIEEE(d.crc, p) - default: - d.crc = simpleUpdate(d.crc, d.tab, p) - } - return len(p), nil -} - -func (d *digest) Sum32() uint32 { return d.crc } - -func (d *digest) Sum(in []byte) []byte { - s := d.Sum32() - return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) -} - -// Checksum returns the CRC-32 checksum of data -// using the polynomial represented by the Table. -func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) } - -// ChecksumIEEE returns the CRC-32 checksum of data -// using the IEEE polynomial. -func ChecksumIEEE(data []byte) uint32 { - ieeeOnce.Do(ieeeInit) - return updateIEEE(0, data) -} diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.go b/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.go deleted file mode 100644 index af2a0b8..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine,!gccgo - -// AMD64-specific hardware-assisted CRC32 algorithms. See crc32.go for a -// description of the interface that each architecture-specific file -// implements. - -package crc32 - -import "unsafe" - -// This file contains the code to call the SSE 4.2 version of the Castagnoli -// and IEEE CRC. - -// haveSSE41/haveSSE42/haveCLMUL are defined in crc_amd64.s and use -// CPUID to test for SSE 4.1, 4.2 and CLMUL support. -func haveSSE41() bool -func haveSSE42() bool -func haveCLMUL() bool - -// castagnoliSSE42 is defined in crc32_amd64.s and uses the SSE4.2 CRC32 -// instruction. -//go:noescape -func castagnoliSSE42(crc uint32, p []byte) uint32 - -// castagnoliSSE42Triple is defined in crc32_amd64.s and uses the SSE4.2 CRC32 -// instruction. -//go:noescape -func castagnoliSSE42Triple( - crcA, crcB, crcC uint32, - a, b, c []byte, - rounds uint32, -) (retA uint32, retB uint32, retC uint32) - -// ieeeCLMUL is defined in crc_amd64.s and uses the PCLMULQDQ -// instruction as well as SSE 4.1. -//go:noescape -func ieeeCLMUL(crc uint32, p []byte) uint32 - -var sse42 = haveSSE42() -var useFastIEEE = haveCLMUL() && haveSSE41() - -const castagnoliK1 = 168 -const castagnoliK2 = 1344 - -type sse42Table [4]Table - -var castagnoliSSE42TableK1 *sse42Table -var castagnoliSSE42TableK2 *sse42Table - -func archAvailableCastagnoli() bool { - return sse42 -} - -func archInitCastagnoli() { - if !sse42 { - panic("arch-specific Castagnoli not available") - } - castagnoliSSE42TableK1 = new(sse42Table) - castagnoliSSE42TableK2 = new(sse42Table) - // See description in updateCastagnoli. - // t[0][i] = CRC(i000, O) - // t[1][i] = CRC(0i00, O) - // t[2][i] = CRC(00i0, O) - // t[3][i] = CRC(000i, O) - // where O is a sequence of K zeros. - var tmp [castagnoliK2]byte - for b := 0; b < 4; b++ { - for i := 0; i < 256; i++ { - val := uint32(i) << uint32(b*8) - castagnoliSSE42TableK1[b][i] = castagnoliSSE42(val, tmp[:castagnoliK1]) - castagnoliSSE42TableK2[b][i] = castagnoliSSE42(val, tmp[:]) - } - } -} - -// castagnoliShift computes the CRC32-C of K1 or K2 zeroes (depending on the -// table given) with the given initial crc value. This corresponds to -// CRC(crc, O) in the description in updateCastagnoli. -func castagnoliShift(table *sse42Table, crc uint32) uint32 { - return table[3][crc>>24] ^ - table[2][(crc>>16)&0xFF] ^ - table[1][(crc>>8)&0xFF] ^ - table[0][crc&0xFF] -} - -func archUpdateCastagnoli(crc uint32, p []byte) uint32 { - if !sse42 { - panic("not available") - } - - // This method is inspired from the algorithm in Intel's white paper: - // "Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction" - // The same strategy of splitting the buffer in three is used but the - // combining calculation is different; the complete derivation is explained - // below. - // - // -- The basic idea -- - // - // The CRC32 instruction (available in SSE4.2) can process 8 bytes at a - // time. In recent Intel architectures the instruction takes 3 cycles; - // however the processor can pipeline up to three instructions if they - // don't depend on each other. - // - // Roughly this means that we can process three buffers in about the same - // time we can process one buffer. - // - // The idea is then to split the buffer in three, CRC the three pieces - // separately and then combine the results. - // - // Combining the results requires precomputed tables, so we must choose a - // fixed buffer length to optimize. The longer the length, the faster; but - // only buffers longer than this length will use the optimization. We choose - // two cutoffs and compute tables for both: - // - one around 512: 168*3=504 - // - one around 4KB: 1344*3=4032 - // - // -- The nitty gritty -- - // - // Let CRC(I, X) be the non-inverted CRC32-C of the sequence X (with - // initial non-inverted CRC I). This function has the following properties: - // (a) CRC(I, AB) = CRC(CRC(I, A), B) - // (b) CRC(I, A xor B) = CRC(I, A) xor CRC(0, B) - // - // Say we want to compute CRC(I, ABC) where A, B, C are three sequences of - // K bytes each, where K is a fixed constant. Let O be the sequence of K zero - // bytes. - // - // CRC(I, ABC) = CRC(I, ABO xor C) - // = CRC(I, ABO) xor CRC(0, C) - // = CRC(CRC(I, AB), O) xor CRC(0, C) - // = CRC(CRC(I, AO xor B), O) xor CRC(0, C) - // = CRC(CRC(I, AO) xor CRC(0, B), O) xor CRC(0, C) - // = CRC(CRC(CRC(I, A), O) xor CRC(0, B), O) xor CRC(0, C) - // - // The castagnoliSSE42Triple function can compute CRC(I, A), CRC(0, B), - // and CRC(0, C) efficiently. We just need to find a way to quickly compute - // CRC(uvwx, O) given a 4-byte initial value uvwx. We can precompute these - // values; since we can't have a 32-bit table, we break it up into four - // 8-bit tables: - // - // CRC(uvwx, O) = CRC(u000, O) xor - // CRC(0v00, O) xor - // CRC(00w0, O) xor - // CRC(000x, O) - // - // We can compute tables corresponding to the four terms for all 8-bit - // values. - - crc = ^crc - - // If a buffer is long enough to use the optimization, process the first few - // bytes to align the buffer to an 8 byte boundary (if necessary). - if len(p) >= castagnoliK1*3 { - delta := int(uintptr(unsafe.Pointer(&p[0])) & 7) - if delta != 0 { - delta = 8 - delta - crc = castagnoliSSE42(crc, p[:delta]) - p = p[delta:] - } - } - - // Process 3*K2 at a time. - for len(p) >= castagnoliK2*3 { - // Compute CRC(I, A), CRC(0, B), and CRC(0, C). - crcA, crcB, crcC := castagnoliSSE42Triple( - crc, 0, 0, - p, p[castagnoliK2:], p[castagnoliK2*2:], - castagnoliK2/24) - - // CRC(I, AB) = CRC(CRC(I, A), O) xor CRC(0, B) - crcAB := castagnoliShift(castagnoliSSE42TableK2, crcA) ^ crcB - // CRC(I, ABC) = CRC(CRC(I, AB), O) xor CRC(0, C) - crc = castagnoliShift(castagnoliSSE42TableK2, crcAB) ^ crcC - p = p[castagnoliK2*3:] - } - - // Process 3*K1 at a time. - for len(p) >= castagnoliK1*3 { - // Compute CRC(I, A), CRC(0, B), and CRC(0, C). - crcA, crcB, crcC := castagnoliSSE42Triple( - crc, 0, 0, - p, p[castagnoliK1:], p[castagnoliK1*2:], - castagnoliK1/24) - - // CRC(I, AB) = CRC(CRC(I, A), O) xor CRC(0, B) - crcAB := castagnoliShift(castagnoliSSE42TableK1, crcA) ^ crcB - // CRC(I, ABC) = CRC(CRC(I, AB), O) xor CRC(0, C) - crc = castagnoliShift(castagnoliSSE42TableK1, crcAB) ^ crcC - p = p[castagnoliK1*3:] - } - - // Use the simple implementation for what's left. - crc = castagnoliSSE42(crc, p) - return ^crc -} - -func archAvailableIEEE() bool { - return useFastIEEE -} - -var archIeeeTable8 *slicing8Table - -func archInitIEEE() { - if !useFastIEEE { - panic("not available") - } - // We still use slicing-by-8 for small buffers. - archIeeeTable8 = slicingMakeTable(IEEE) -} - -func archUpdateIEEE(crc uint32, p []byte) uint32 { - if !useFastIEEE { - panic("not available") - } - - if len(p) >= 64 { - left := len(p) & 15 - do := len(p) - left - crc = ^ieeeCLMUL(^crc, p[:do]) - p = p[do:] - } - if len(p) == 0 { - return crc - } - return slicingUpdate(crc, archIeeeTable8, p) -} diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.s b/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.s deleted file mode 100644 index e8a7941..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.s +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build gc - -#define NOSPLIT 4 -#define RODATA 8 - -// castagnoliSSE42 updates the (non-inverted) crc with the given buffer. -// -// func castagnoliSSE42(crc uint32, p []byte) uint32 -TEXT ·castagnoliSSE42(SB), NOSPLIT, $0 - MOVL crc+0(FP), AX // CRC value - MOVQ p+8(FP), SI // data pointer - MOVQ p_len+16(FP), CX // len(p) - - // If there are fewer than 8 bytes to process, skip alignment. - CMPQ CX, $8 - JL less_than_8 - - MOVQ SI, BX - ANDQ $7, BX - JZ aligned - - // Process the first few bytes to 8-byte align the input. - - // BX = 8 - BX. We need to process this many bytes to align. - SUBQ $1, BX - XORQ $7, BX - - BTQ $0, BX - JNC align_2 - - CRC32B (SI), AX - DECQ CX - INCQ SI - -align_2: - BTQ $1, BX - JNC align_4 - - // CRC32W (SI), AX - BYTE $0x66; BYTE $0xf2; BYTE $0x0f; BYTE $0x38; BYTE $0xf1; BYTE $0x06 - - SUBQ $2, CX - ADDQ $2, SI - -align_4: - BTQ $2, BX - JNC aligned - - // CRC32L (SI), AX - BYTE $0xf2; BYTE $0x0f; BYTE $0x38; BYTE $0xf1; BYTE $0x06 - - SUBQ $4, CX - ADDQ $4, SI - -aligned: - // The input is now 8-byte aligned and we can process 8-byte chunks. - CMPQ CX, $8 - JL less_than_8 - - CRC32Q (SI), AX - ADDQ $8, SI - SUBQ $8, CX - JMP aligned - -less_than_8: - // We may have some bytes left over; process 4 bytes, then 2, then 1. - BTQ $2, CX - JNC less_than_4 - - // CRC32L (SI), AX - BYTE $0xf2; BYTE $0x0f; BYTE $0x38; BYTE $0xf1; BYTE $0x06 - ADDQ $4, SI - -less_than_4: - BTQ $1, CX - JNC less_than_2 - - // CRC32W (SI), AX - BYTE $0x66; BYTE $0xf2; BYTE $0x0f; BYTE $0x38; BYTE $0xf1; BYTE $0x06 - ADDQ $2, SI - -less_than_2: - BTQ $0, CX - JNC done - - CRC32B (SI), AX - -done: - MOVL AX, ret+32(FP) - RET - -// castagnoliSSE42Triple updates three (non-inverted) crcs with (24*rounds) -// bytes from each buffer. -// -// func castagnoliSSE42Triple( -// crc1, crc2, crc3 uint32, -// a, b, c []byte, -// rounds uint32, -// ) (retA uint32, retB uint32, retC uint32) -TEXT ·castagnoliSSE42Triple(SB), NOSPLIT, $0 - MOVL crcA+0(FP), AX - MOVL crcB+4(FP), CX - MOVL crcC+8(FP), DX - - MOVQ a+16(FP), R8 // data pointer - MOVQ b+40(FP), R9 // data pointer - MOVQ c+64(FP), R10 // data pointer - - MOVL rounds+88(FP), R11 - -loop: - CRC32Q (R8), AX - CRC32Q (R9), CX - CRC32Q (R10), DX - - CRC32Q 8(R8), AX - CRC32Q 8(R9), CX - CRC32Q 8(R10), DX - - CRC32Q 16(R8), AX - CRC32Q 16(R9), CX - CRC32Q 16(R10), DX - - ADDQ $24, R8 - ADDQ $24, R9 - ADDQ $24, R10 - - DECQ R11 - JNZ loop - - MOVL AX, retA+96(FP) - MOVL CX, retB+100(FP) - MOVL DX, retC+104(FP) - RET - -// func haveSSE42() bool -TEXT ·haveSSE42(SB), NOSPLIT, $0 - XORQ AX, AX - INCL AX - CPUID - SHRQ $20, CX - ANDQ $1, CX - MOVB CX, ret+0(FP) - RET - -// func haveCLMUL() bool -TEXT ·haveCLMUL(SB), NOSPLIT, $0 - XORQ AX, AX - INCL AX - CPUID - SHRQ $1, CX - ANDQ $1, CX - MOVB CX, ret+0(FP) - RET - -// func haveSSE41() bool -TEXT ·haveSSE41(SB), NOSPLIT, $0 - XORQ AX, AX - INCL AX - CPUID - SHRQ $19, CX - ANDQ $1, CX - MOVB CX, ret+0(FP) - RET - -// CRC32 polynomial data -// -// These constants are lifted from the -// Linux kernel, since they avoid the costly -// PSHUFB 16 byte reversal proposed in the -// original Intel paper. -DATA r2r1kp<>+0(SB)/8, $0x154442bd4 -DATA r2r1kp<>+8(SB)/8, $0x1c6e41596 -DATA r4r3kp<>+0(SB)/8, $0x1751997d0 -DATA r4r3kp<>+8(SB)/8, $0x0ccaa009e -DATA rupolykp<>+0(SB)/8, $0x1db710641 -DATA rupolykp<>+8(SB)/8, $0x1f7011641 -DATA r5kp<>+0(SB)/8, $0x163cd6124 - -GLOBL r2r1kp<>(SB), RODATA, $16 -GLOBL r4r3kp<>(SB), RODATA, $16 -GLOBL rupolykp<>(SB), RODATA, $16 -GLOBL r5kp<>(SB), RODATA, $8 - -// Based on http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf -// len(p) must be at least 64, and must be a multiple of 16. - -// func ieeeCLMUL(crc uint32, p []byte) uint32 -TEXT ·ieeeCLMUL(SB), NOSPLIT, $0 - MOVL crc+0(FP), X0 // Initial CRC value - MOVQ p+8(FP), SI // data pointer - MOVQ p_len+16(FP), CX // len(p) - - MOVOU (SI), X1 - MOVOU 16(SI), X2 - MOVOU 32(SI), X3 - MOVOU 48(SI), X4 - PXOR X0, X1 - ADDQ $64, SI // buf+=64 - SUBQ $64, CX // len-=64 - CMPQ CX, $64 // Less than 64 bytes left - JB remain64 - - MOVOA r2r1kp<>+0(SB), X0 - -loopback64: - MOVOA X1, X5 - MOVOA X2, X6 - MOVOA X3, X7 - MOVOA X4, X8 - - PCLMULQDQ $0, X0, X1 - PCLMULQDQ $0, X0, X2 - PCLMULQDQ $0, X0, X3 - PCLMULQDQ $0, X0, X4 - - // Load next early - MOVOU (SI), X11 - MOVOU 16(SI), X12 - MOVOU 32(SI), X13 - MOVOU 48(SI), X14 - - PCLMULQDQ $0x11, X0, X5 - PCLMULQDQ $0x11, X0, X6 - PCLMULQDQ $0x11, X0, X7 - PCLMULQDQ $0x11, X0, X8 - - PXOR X5, X1 - PXOR X6, X2 - PXOR X7, X3 - PXOR X8, X4 - - PXOR X11, X1 - PXOR X12, X2 - PXOR X13, X3 - PXOR X14, X4 - - ADDQ $0x40, DI - ADDQ $64, SI // buf+=64 - SUBQ $64, CX // len-=64 - CMPQ CX, $64 // Less than 64 bytes left? - JGE loopback64 - - // Fold result into a single register (X1) -remain64: - MOVOA r4r3kp<>+0(SB), X0 - - MOVOA X1, X5 - PCLMULQDQ $0, X0, X1 - PCLMULQDQ $0x11, X0, X5 - PXOR X5, X1 - PXOR X2, X1 - - MOVOA X1, X5 - PCLMULQDQ $0, X0, X1 - PCLMULQDQ $0x11, X0, X5 - PXOR X5, X1 - PXOR X3, X1 - - MOVOA X1, X5 - PCLMULQDQ $0, X0, X1 - PCLMULQDQ $0x11, X0, X5 - PXOR X5, X1 - PXOR X4, X1 - - // If there is less than 16 bytes left we are done - CMPQ CX, $16 - JB finish - - // Encode 16 bytes -remain16: - MOVOU (SI), X10 - MOVOA X1, X5 - PCLMULQDQ $0, X0, X1 - PCLMULQDQ $0x11, X0, X5 - PXOR X5, X1 - PXOR X10, X1 - SUBQ $16, CX - ADDQ $16, SI - CMPQ CX, $16 - JGE remain16 - -finish: - // Fold final result into 32 bits and return it - PCMPEQB X3, X3 - PCLMULQDQ $1, X1, X0 - PSRLDQ $8, X1 - PXOR X0, X1 - - MOVOA X1, X2 - MOVQ r5kp<>+0(SB), X0 - - // Creates 32 bit mask. Note that we don't care about upper half. - PSRLQ $32, X3 - - PSRLDQ $4, X2 - PAND X3, X1 - PCLMULQDQ $0, X0, X1 - PXOR X2, X1 - - MOVOA rupolykp<>+0(SB), X0 - - MOVOA X1, X2 - PAND X3, X1 - PCLMULQDQ $0x10, X0, X1 - PAND X3, X1 - PCLMULQDQ $0, X0, X1 - PXOR X2, X1 - - // PEXTRD $1, X1, AX (SSE 4.1) - BYTE $0x66; BYTE $0x0f; BYTE $0x3a - BYTE $0x16; BYTE $0xc8; BYTE $0x01 - MOVL AX, ret+32(FP) - - RET diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.go b/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.go deleted file mode 100644 index 3222b06..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine,!gccgo - -package crc32 - -// This file contains the code to call the SSE 4.2 version of the Castagnoli -// CRC. - -// haveSSE42 is defined in crc32_amd64p32.s and uses CPUID to test for SSE 4.2 -// support. -func haveSSE42() bool - -// castagnoliSSE42 is defined in crc32_amd64p32.s and uses the SSE4.2 CRC32 -// instruction. -//go:noescape -func castagnoliSSE42(crc uint32, p []byte) uint32 - -var sse42 = haveSSE42() - -func archAvailableCastagnoli() bool { - return sse42 -} - -func archInitCastagnoli() { - if !sse42 { - panic("not available") - } - // No initialization necessary. -} - -func archUpdateCastagnoli(crc uint32, p []byte) uint32 { - if !sse42 { - panic("not available") - } - return castagnoliSSE42(crc, p) -} - -func archAvailableIEEE() bool { return false } -func archInitIEEE() { panic("not available") } -func archUpdateIEEE(crc uint32, p []byte) uint32 { panic("not available") } diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.s b/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.s deleted file mode 100644 index a578d68..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.s +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build gc - -#define NOSPLIT 4 -#define RODATA 8 - -// func castagnoliSSE42(crc uint32, p []byte) uint32 -TEXT ·castagnoliSSE42(SB), NOSPLIT, $0 - MOVL crc+0(FP), AX // CRC value - MOVL p+4(FP), SI // data pointer - MOVL p_len+8(FP), CX // len(p) - - NOTL AX - - // If there's less than 8 bytes to process, we do it byte-by-byte. - CMPQ CX, $8 - JL cleanup - - // Process individual bytes until the input is 8-byte aligned. -startup: - MOVQ SI, BX - ANDQ $7, BX - JZ aligned - - CRC32B (SI), AX - DECQ CX - INCQ SI - JMP startup - -aligned: - // The input is now 8-byte aligned and we can process 8-byte chunks. - CMPQ CX, $8 - JL cleanup - - CRC32Q (SI), AX - ADDQ $8, SI - SUBQ $8, CX - JMP aligned - -cleanup: - // We may have some bytes left over that we process one at a time. - CMPQ CX, $0 - JE done - - CRC32B (SI), AX - INCQ SI - DECQ CX - JMP cleanup - -done: - NOTL AX - MOVL AX, ret+16(FP) - RET - -// func haveSSE42() bool -TEXT ·haveSSE42(SB), NOSPLIT, $0 - XORQ AX, AX - INCL AX - CPUID - SHRQ $20, CX - ANDQ $1, CX - MOVB CX, ret+0(FP) - RET - diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_generic.go b/cmd/gost/vendor/github.com/klauspost/crc32/crc32_generic.go deleted file mode 100644 index abacbb6..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_generic.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file contains CRC32 algorithms that are not specific to any architecture -// and don't use hardware acceleration. -// -// The simple (and slow) CRC32 implementation only uses a 256*4 bytes table. -// -// The slicing-by-8 algorithm is a faster implementation that uses a bigger -// table (8*256*4 bytes). - -package crc32 - -// simpleMakeTable allocates and constructs a Table for the specified -// polynomial. The table is suitable for use with the simple algorithm -// (simpleUpdate). -func simpleMakeTable(poly uint32) *Table { - t := new(Table) - simplePopulateTable(poly, t) - return t -} - -// simplePopulateTable constructs a Table for the specified polynomial, suitable -// for use with simpleUpdate. -func simplePopulateTable(poly uint32, t *Table) { - for i := 0; i < 256; i++ { - crc := uint32(i) - for j := 0; j < 8; j++ { - if crc&1 == 1 { - crc = (crc >> 1) ^ poly - } else { - crc >>= 1 - } - } - t[i] = crc - } -} - -// simpleUpdate uses the simple algorithm to update the CRC, given a table that -// was previously computed using simpleMakeTable. -func simpleUpdate(crc uint32, tab *Table, p []byte) uint32 { - crc = ^crc - for _, v := range p { - crc = tab[byte(crc)^v] ^ (crc >> 8) - } - return ^crc -} - -// Use slicing-by-8 when payload >= this value. -const slicing8Cutoff = 16 - -// slicing8Table is array of 8 Tables, used by the slicing-by-8 algorithm. -type slicing8Table [8]Table - -// slicingMakeTable constructs a slicing8Table for the specified polynomial. The -// table is suitable for use with the slicing-by-8 algorithm (slicingUpdate). -func slicingMakeTable(poly uint32) *slicing8Table { - t := new(slicing8Table) - simplePopulateTable(poly, &t[0]) - for i := 0; i < 256; i++ { - crc := t[0][i] - for j := 1; j < 8; j++ { - crc = t[0][crc&0xFF] ^ (crc >> 8) - t[j][i] = crc - } - } - return t -} - -// slicingUpdate uses the slicing-by-8 algorithm to update the CRC, given a -// table that was previously computed using slicingMakeTable. -func slicingUpdate(crc uint32, tab *slicing8Table, p []byte) uint32 { - if len(p) >= slicing8Cutoff { - crc = ^crc - for len(p) > 8 { - crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 - crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^ - tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^ - tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF] - p = p[8:] - } - crc = ^crc - } - if len(p) == 0 { - return crc - } - return simpleUpdate(crc, &tab[0], p) -} diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_otherarch.go b/cmd/gost/vendor/github.com/klauspost/crc32/crc32_otherarch.go deleted file mode 100644 index cc96076..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_otherarch.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !amd64,!amd64p32,!s390x - -package crc32 - -func archAvailableIEEE() bool { return false } -func archInitIEEE() { panic("not available") } -func archUpdateIEEE(crc uint32, p []byte) uint32 { panic("not available") } - -func archAvailableCastagnoli() bool { return false } -func archInitCastagnoli() { panic("not available") } -func archUpdateCastagnoli(crc uint32, p []byte) uint32 { panic("not available") } diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.go b/cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.go deleted file mode 100644 index ce96f03..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build s390x - -package crc32 - -const ( - vxMinLen = 64 - vxAlignMask = 15 // align to 16 bytes -) - -// hasVectorFacility reports whether the machine has the z/Architecture -// vector facility installed and enabled. -func hasVectorFacility() bool - -var hasVX = hasVectorFacility() - -// vectorizedCastagnoli implements CRC32 using vector instructions. -// It is defined in crc32_s390x.s. -//go:noescape -func vectorizedCastagnoli(crc uint32, p []byte) uint32 - -// vectorizedIEEE implements CRC32 using vector instructions. -// It is defined in crc32_s390x.s. -//go:noescape -func vectorizedIEEE(crc uint32, p []byte) uint32 - -func archAvailableCastagnoli() bool { - return hasVX -} - -var archCastagnoliTable8 *slicing8Table - -func archInitCastagnoli() { - if !hasVX { - panic("not available") - } - // We still use slicing-by-8 for small buffers. - archCastagnoliTable8 = slicingMakeTable(Castagnoli) -} - -// archUpdateCastagnoli calculates the checksum of p using -// vectorizedCastagnoli. -func archUpdateCastagnoli(crc uint32, p []byte) uint32 { - if !hasVX { - panic("not available") - } - // Use vectorized function if data length is above threshold. - if len(p) >= vxMinLen { - aligned := len(p) & ^vxAlignMask - crc = vectorizedCastagnoli(crc, p[:aligned]) - p = p[aligned:] - } - if len(p) == 0 { - return crc - } - return slicingUpdate(crc, archCastagnoliTable8, p) -} - -func archAvailableIEEE() bool { - return hasVX -} - -var archIeeeTable8 *slicing8Table - -func archInitIEEE() { - if !hasVX { - panic("not available") - } - // We still use slicing-by-8 for small buffers. - archIeeeTable8 = slicingMakeTable(IEEE) -} - -// archUpdateIEEE calculates the checksum of p using vectorizedIEEE. -func archUpdateIEEE(crc uint32, p []byte) uint32 { - if !hasVX { - panic("not available") - } - // Use vectorized function if data length is above threshold. - if len(p) >= vxMinLen { - aligned := len(p) & ^vxAlignMask - crc = vectorizedIEEE(crc, p[:aligned]) - p = p[aligned:] - } - if len(p) == 0 { - return crc - } - return slicingUpdate(crc, archIeeeTable8, p) -} diff --git a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.s b/cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.s deleted file mode 100644 index e980ca2..0000000 --- a/cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.s +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build s390x - -#include "textflag.h" - -// Vector register range containing CRC-32 constants - -#define CONST_PERM_LE2BE V9 -#define CONST_R2R1 V10 -#define CONST_R4R3 V11 -#define CONST_R5 V12 -#define CONST_RU_POLY V13 -#define CONST_CRC_POLY V14 - -// The CRC-32 constant block contains reduction constants to fold and -// process particular chunks of the input data stream in parallel. -// -// Note that the constant definitions below are extended in order to compute -// intermediate results with a single VECTOR GALOIS FIELD MULTIPLY instruction. -// The rightmost doubleword can be 0 to prevent contribution to the result or -// can be multiplied by 1 to perform an XOR without the need for a separate -// VECTOR EXCLUSIVE OR instruction. -// -// The polynomials used are bit-reflected: -// -// IEEE: P'(x) = 0x0edb88320 -// Castagnoli: P'(x) = 0x082f63b78 - -// IEEE polynomial constants -DATA ·crcleconskp+0(SB)/8, $0x0F0E0D0C0B0A0908 // LE-to-BE mask -DATA ·crcleconskp+8(SB)/8, $0x0706050403020100 -DATA ·crcleconskp+16(SB)/8, $0x00000001c6e41596 // R2 -DATA ·crcleconskp+24(SB)/8, $0x0000000154442bd4 // R1 -DATA ·crcleconskp+32(SB)/8, $0x00000000ccaa009e // R4 -DATA ·crcleconskp+40(SB)/8, $0x00000001751997d0 // R3 -DATA ·crcleconskp+48(SB)/8, $0x0000000000000000 -DATA ·crcleconskp+56(SB)/8, $0x0000000163cd6124 // R5 -DATA ·crcleconskp+64(SB)/8, $0x0000000000000000 -DATA ·crcleconskp+72(SB)/8, $0x00000001F7011641 // u' -DATA ·crcleconskp+80(SB)/8, $0x0000000000000000 -DATA ·crcleconskp+88(SB)/8, $0x00000001DB710641 // P'(x) << 1 - -GLOBL ·crcleconskp(SB), RODATA, $144 - -// Castagonli Polynomial constants -DATA ·crccleconskp+0(SB)/8, $0x0F0E0D0C0B0A0908 // LE-to-BE mask -DATA ·crccleconskp+8(SB)/8, $0x0706050403020100 -DATA ·crccleconskp+16(SB)/8, $0x000000009e4addf8 // R2 -DATA ·crccleconskp+24(SB)/8, $0x00000000740eef02 // R1 -DATA ·crccleconskp+32(SB)/8, $0x000000014cd00bd6 // R4 -DATA ·crccleconskp+40(SB)/8, $0x00000000f20c0dfe // R3 -DATA ·crccleconskp+48(SB)/8, $0x0000000000000000 -DATA ·crccleconskp+56(SB)/8, $0x00000000dd45aab8 // R5 -DATA ·crccleconskp+64(SB)/8, $0x0000000000000000 -DATA ·crccleconskp+72(SB)/8, $0x00000000dea713f1 // u' -DATA ·crccleconskp+80(SB)/8, $0x0000000000000000 -DATA ·crccleconskp+88(SB)/8, $0x0000000105ec76f0 // P'(x) << 1 - -GLOBL ·crccleconskp(SB), RODATA, $144 - -// func hasVectorFacility() bool -TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 - MOVD $x-24(SP), R1 - XC $24, 0(R1), 0(R1) // clear the storage - MOVD $2, R0 // R0 is the number of double words stored -1 - WORD $0xB2B01000 // STFLE 0(R1) - XOR R0, R0 // reset the value of R0 - MOVBZ z-8(SP), R1 - AND $0x40, R1 - BEQ novector - -vectorinstalled: - // check if the vector instruction has been enabled - VLEIB $0, $0xF, V16 - VLGVB $0, V16, R1 - CMPBNE R1, $0xF, novector - MOVB $1, ret+0(FP) // have vx - RET - -novector: - MOVB $0, ret+0(FP) // no vx - RET - -// The CRC-32 function(s) use these calling conventions: -// -// Parameters: -// -// R2: Initial CRC value, typically ~0; and final CRC (return) value. -// R3: Input buffer pointer, performance might be improved if the -// buffer is on a doubleword boundary. -// R4: Length of the buffer, must be 64 bytes or greater. -// -// Register usage: -// -// R5: CRC-32 constant pool base pointer. -// V0: Initial CRC value and intermediate constants and results. -// V1..V4: Data for CRC computation. -// V5..V8: Next data chunks that are fetched from the input buffer. -// -// V9..V14: CRC-32 constants. - -// func vectorizedIEEE(crc uint32, p []byte) uint32 -TEXT ·vectorizedIEEE(SB), NOSPLIT, $0 - MOVWZ crc+0(FP), R2 // R2 stores the CRC value - MOVD p+8(FP), R3 // data pointer - MOVD p_len+16(FP), R4 // len(p) - - MOVD $·crcleconskp(SB), R5 - BR vectorizedBody<>(SB) - -// func vectorizedCastagnoli(crc uint32, p []byte) uint32 -TEXT ·vectorizedCastagnoli(SB), NOSPLIT, $0 - MOVWZ crc+0(FP), R2 // R2 stores the CRC value - MOVD p+8(FP), R3 // data pointer - MOVD p_len+16(FP), R4 // len(p) - - // R5: crc-32 constant pool base pointer, constant is used to reduce crc - MOVD $·crccleconskp(SB), R5 - BR vectorizedBody<>(SB) - -TEXT vectorizedBody<>(SB), NOSPLIT, $0 - XOR $0xffffffff, R2 // NOTW R2 - VLM 0(R5), CONST_PERM_LE2BE, CONST_CRC_POLY - - // Load the initial CRC value into the rightmost word of V0 - VZERO V0 - VLVGF $3, R2, V0 - - // Crash if the input size is less than 64-bytes. - CMP R4, $64 - BLT crash - - // Load a 64-byte data chunk and XOR with CRC - VLM 0(R3), V1, V4 // 64-bytes into V1..V4 - - // Reflect the data if the CRC operation is in the bit-reflected domain - VPERM V1, V1, CONST_PERM_LE2BE, V1 - VPERM V2, V2, CONST_PERM_LE2BE, V2 - VPERM V3, V3, CONST_PERM_LE2BE, V3 - VPERM V4, V4, CONST_PERM_LE2BE, V4 - - VX V0, V1, V1 // V1 ^= CRC - ADD $64, R3 // BUF = BUF + 64 - ADD $(-64), R4 - - // Check remaining buffer size and jump to proper folding method - CMP R4, $64 - BLT less_than_64bytes - -fold_64bytes_loop: - // Load the next 64-byte data chunk into V5 to V8 - VLM 0(R3), V5, V8 - VPERM V5, V5, CONST_PERM_LE2BE, V5 - VPERM V6, V6, CONST_PERM_LE2BE, V6 - VPERM V7, V7, CONST_PERM_LE2BE, V7 - VPERM V8, V8, CONST_PERM_LE2BE, V8 - - // Perform a GF(2) multiplication of the doublewords in V1 with - // the reduction constants in V0. The intermediate result is - // then folded (accumulated) with the next data chunk in V5 and - // stored in V1. Repeat this step for the register contents - // in V2, V3, and V4 respectively. - - VGFMAG CONST_R2R1, V1, V5, V1 - VGFMAG CONST_R2R1, V2, V6, V2 - VGFMAG CONST_R2R1, V3, V7, V3 - VGFMAG CONST_R2R1, V4, V8, V4 - - // Adjust buffer pointer and length for next loop - ADD $64, R3 // BUF = BUF + 64 - ADD $(-64), R4 // LEN = LEN - 64 - - CMP R4, $64 - BGE fold_64bytes_loop - -less_than_64bytes: - // Fold V1 to V4 into a single 128-bit value in V1 - VGFMAG CONST_R4R3, V1, V2, V1 - VGFMAG CONST_R4R3, V1, V3, V1 - VGFMAG CONST_R4R3, V1, V4, V1 - - // Check whether to continue with 64-bit folding - CMP R4, $16 - BLT final_fold - -fold_16bytes_loop: - VL 0(R3), V2 // Load next data chunk - VPERM V2, V2, CONST_PERM_LE2BE, V2 - - VGFMAG CONST_R4R3, V1, V2, V1 // Fold next data chunk - - // Adjust buffer pointer and size for folding next data chunk - ADD $16, R3 - ADD $-16, R4 - - // Process remaining data chunks - CMP R4, $16 - BGE fold_16bytes_loop - -final_fold: - VLEIB $7, $0x40, V9 - VSRLB V9, CONST_R4R3, V0 - VLEIG $0, $1, V0 - - VGFMG V0, V1, V1 - - VLEIB $7, $0x20, V9 // Shift by words - VSRLB V9, V1, V2 // Store remaining bits in V2 - VUPLLF V1, V1 // Split rightmost doubleword - VGFMAG CONST_R5, V1, V2, V1 // V1 = (V1 * R5) XOR V2 - - // The input values to the Barret reduction are the degree-63 polynomial - // in V1 (R(x)), degree-32 generator polynomial, and the reduction - // constant u. The Barret reduction result is the CRC value of R(x) mod - // P(x). - // - // The Barret reduction algorithm is defined as: - // - // 1. T1(x) = floor( R(x) / x^32 ) GF2MUL u - // 2. T2(x) = floor( T1(x) / x^32 ) GF2MUL P(x) - // 3. C(x) = R(x) XOR T2(x) mod x^32 - // - // Note: To compensate the division by x^32, use the vector unpack - // instruction to move the leftmost word into the leftmost doubleword - // of the vector register. The rightmost doubleword is multiplied - // with zero to not contribute to the intermedate results. - - // T1(x) = floor( R(x) / x^32 ) GF2MUL u - VUPLLF V1, V2 - VGFMG CONST_RU_POLY, V2, V2 - - // Compute the GF(2) product of the CRC polynomial in VO with T1(x) in - // V2 and XOR the intermediate result, T2(x), with the value in V1. - // The final result is in the rightmost word of V2. - - VUPLLF V2, V2 - VGFMAG CONST_CRC_POLY, V2, V1, V2 - -done: - VLGVF $2, V2, R2 - XOR $0xffffffff, R2 // NOTW R2 - MOVWZ R2, ret + 32(FP) - RET - -crash: - MOVD $0, (R0) // input size is less than 64-bytes diff --git a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/README.md b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/README.md index 3f34820..c8139b3 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/README.md +++ b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/README.md @@ -1,4 +1,5 @@ -# kcp-go +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] @@ -19,12 +20,12 @@ ## 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. +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. Optimized for ***Online Games, Audio/Video Streaming***. +1. Compatible with [skywind3000's](https://github.com/skywind3000) C version with optimizations. 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) @@ -40,7 +41,7 @@ For complete documentation, see the associated [Godoc](https://godoc.org/github. ## Specification -# Frame Format +Frame Format ## Usage @@ -75,14 +76,14 @@ PASS ok github.com/xtaci/kcp-go 0.600s ``` +## Who is using this? + +1. https://github.com/xtaci/kcptun +2. https://github.com/getlantern/lantern +3. https://github.com/smallnest/rpcx + ## Links -1. https://github.com/xtaci/libkcp -- Official client library for iOS/Android(C++11) +1. https://github.com/xtaci/libkcp -- FEC enhanced KCP session library for iOS/Android in C++ 2. https://github.com/skywind3000/kcp -- A Fast and Reliable ARQ Protocol 3. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go - -## 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/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/crypt.go b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/crypt.go index df85278..2e456b8 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/crypt.go +++ b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/crypt.go @@ -20,7 +20,9 @@ var ( saltxor = `sH3CIVoF#rWLtJo6` ) -// BlockCrypt defines encryption/decryption methods for a given byte slice +// 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. @@ -31,40 +33,35 @@ type BlockCrypt interface { Decrypt(dst, src []byte) } -// Salsa20BlockCrypt implements BlockCrypt -type Salsa20BlockCrypt struct { +type salsa20BlockCrypt struct { key [32]byte } -// NewSalsa20BlockCrypt initates BlockCrypt by the given key +// NewSalsa20BlockCrypt https://en.wikipedia.org/wiki/Salsa20 func NewSalsa20BlockCrypt(key []byte) (BlockCrypt, error) { - c := new(Salsa20BlockCrypt) + c := new(salsa20BlockCrypt) copy(c.key[:], key) return c, nil } -// Encrypt implements Encrypt interface -func (c *Salsa20BlockCrypt) Encrypt(dst, src []byte) { +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]) } -// Decrypt implements Decrypt interface -func (c *Salsa20BlockCrypt) Decrypt(dst, src []byte) { - salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key) - copy(dst[:8], src[:8]) -} - -// TwofishBlockCrypt implements BlockCrypt -type TwofishBlockCrypt struct { +type twofishBlockCrypt struct { encbuf []byte decbuf []byte block cipher.Block } -// NewTwofishBlockCrypt initates BlockCrypt by the given key +// NewTwofishBlockCrypt https://en.wikipedia.org/wiki/Twofish func NewTwofishBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(TwofishBlockCrypt) + c := new(twofishBlockCrypt) block, err := twofish.NewCipher(key) if err != nil { return nil, err @@ -75,22 +72,18 @@ func NewTwofishBlockCrypt(key []byte) (BlockCrypt, error) { return c, nil } -// Encrypt implements Encrypt interface -func (c *TwofishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) } +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) } -// Decrypt implements Decrypt interface -func (c *TwofishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) } - -// TripleDESBlockCrypt implements BlockCrypt -type TripleDESBlockCrypt struct { +type tripleDESBlockCrypt struct { encbuf []byte decbuf []byte block cipher.Block } -// NewTripleDESBlockCrypt initates BlockCrypt by the given key +// NewTripleDESBlockCrypt https://en.wikipedia.org/wiki/Triple_DES func NewTripleDESBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(TripleDESBlockCrypt) + c := new(tripleDESBlockCrypt) block, err := des.NewTripleDESCipher(key) if err != nil { return nil, err @@ -101,22 +94,18 @@ func NewTripleDESBlockCrypt(key []byte) (BlockCrypt, error) { return c, nil } -// Encrypt implements Encrypt interface -func (c *TripleDESBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) } +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) } -// Decrypt implements Decrypt interface -func (c *TripleDESBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) } - -// Cast5BlockCrypt implements BlockCrypt -type Cast5BlockCrypt struct { +type cast5BlockCrypt struct { encbuf []byte decbuf []byte block cipher.Block } -// NewCast5BlockCrypt initates BlockCrypt by the given key +// NewCast5BlockCrypt https://en.wikipedia.org/wiki/CAST-128 func NewCast5BlockCrypt(key []byte) (BlockCrypt, error) { - c := new(Cast5BlockCrypt) + c := new(cast5BlockCrypt) block, err := cast5.NewCipher(key) if err != nil { return nil, err @@ -127,22 +116,18 @@ func NewCast5BlockCrypt(key []byte) (BlockCrypt, error) { return c, nil } -// Encrypt implements Encrypt interface -func (c *Cast5BlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) } +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) } -// Decrypt implements Decrypt interface -func (c *Cast5BlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) } - -// BlowfishBlockCrypt implements BlockCrypt -type BlowfishBlockCrypt struct { +type blowfishBlockCrypt struct { encbuf []byte decbuf []byte block cipher.Block } -// NewBlowfishBlockCrypt initates BlockCrypt by the given key +// NewBlowfishBlockCrypt https://en.wikipedia.org/wiki/Blowfish_(cipher) func NewBlowfishBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(BlowfishBlockCrypt) + c := new(blowfishBlockCrypt) block, err := blowfish.NewCipher(key) if err != nil { return nil, err @@ -153,22 +138,18 @@ func NewBlowfishBlockCrypt(key []byte) (BlockCrypt, error) { return c, nil } -// Encrypt implements Encrypt interface -func (c *BlowfishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) } +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) } -// Decrypt implements Decrypt interface -func (c *BlowfishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) } - -// AESBlockCrypt implements BlockCrypt -type AESBlockCrypt struct { +type aesBlockCrypt struct { encbuf []byte decbuf []byte block cipher.Block } -// NewAESBlockCrypt initates BlockCrypt by the given key +// NewAESBlockCrypt https://en.wikipedia.org/wiki/Advanced_Encryption_Standard func NewAESBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(AESBlockCrypt) + c := new(aesBlockCrypt) block, err := aes.NewCipher(key) if err != nil { return nil, err @@ -179,22 +160,18 @@ func NewAESBlockCrypt(key []byte) (BlockCrypt, error) { return c, nil } -// Encrypt implements Encrypt interface -func (c *AESBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) } +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) } -// Decrypt implements Decrypt interface -func (c *AESBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) } - -// TEABlockCrypt implements BlockCrypt -type TEABlockCrypt struct { +type teaBlockCrypt struct { encbuf []byte decbuf []byte block cipher.Block } -// NewTEABlockCrypt initate BlockCrypt by the given key +// NewTEABlockCrypt https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm func NewTEABlockCrypt(key []byte) (BlockCrypt, error) { - c := new(TEABlockCrypt) + c := new(teaBlockCrypt) block, err := tea.NewCipherWithRounds(key, 16) if err != nil { return nil, err @@ -205,22 +182,18 @@ func NewTEABlockCrypt(key []byte) (BlockCrypt, error) { return c, nil } -// Encrypt implements Encrypt interface -func (c *TEABlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) } +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) } -// Decrypt implements Decrypt interface -func (c *TEABlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) } - -// XTEABlockCrypt implements BlockCrypt -type XTEABlockCrypt struct { +type xteaBlockCrypt struct { encbuf []byte decbuf []byte block cipher.Block } -// NewXTEABlockCrypt initate BlockCrypt by the given key +// NewXTEABlockCrypt https://en.wikipedia.org/wiki/XTEA func NewXTEABlockCrypt(key []byte) (BlockCrypt, error) { - c := new(XTEABlockCrypt) + c := new(xteaBlockCrypt) block, err := xtea.NewCipher(key) if err != nil { return nil, err @@ -231,43 +204,32 @@ func NewXTEABlockCrypt(key []byte) (BlockCrypt, error) { return c, nil } -// Encrypt implements Encrypt interface -func (c *XTEABlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) } +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) } -// Decrypt implements Decrypt interface -func (c *XTEABlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) } - -// SimpleXORBlockCrypt implements BlockCrypt -type SimpleXORBlockCrypt struct { +type simpleXORBlockCrypt struct { xortbl []byte } -// NewSimpleXORBlockCrypt initate BlockCrypt by the given key +// NewSimpleXORBlockCrypt simple xor with key expanding func NewSimpleXORBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(SimpleXORBlockCrypt) + c := new(simpleXORBlockCrypt) c.xortbl = pbkdf2.Key(key, []byte(saltxor), 32, mtuLimit, sha1.New) return c, nil } -// Encrypt implements Encrypt interface -func (c *SimpleXORBlockCrypt) Encrypt(dst, src []byte) { xorBytes(dst, src, c.xortbl) } +func (c *simpleXORBlockCrypt) Encrypt(dst, src []byte) { xorBytes(dst, src, c.xortbl) } +func (c *simpleXORBlockCrypt) Decrypt(dst, src []byte) { xorBytes(dst, src, c.xortbl) } -// Decrypt implements Decrypt interface -func (c *SimpleXORBlockCrypt) Decrypt(dst, src []byte) { xorBytes(dst, src, c.xortbl) } +type noneBlockCrypt struct{} -// NoneBlockCrypt simple returns the plaintext -type NoneBlockCrypt struct{} - -// NewNoneBlockCrypt initate by the given key +// NewNoneBlockCrypt does nothing but copying func NewNoneBlockCrypt(key []byte) (BlockCrypt, error) { - return new(NoneBlockCrypt), nil + return new(noneBlockCrypt), nil } -// Encrypt implements Encrypt interface -func (c *NoneBlockCrypt) Encrypt(dst, src []byte) { copy(dst, src) } - -// Decrypt implements Decrypt interface -func (c *NoneBlockCrypt) Decrypt(dst, src []byte) { copy(dst, src) } +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) { diff --git a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/fec.go b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/fec.go index 10ad1c0..25201bb 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/fec.go +++ b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/fec.go @@ -2,7 +2,7 @@ package kcp import ( "encoding/binary" - "sync" + "sync/atomic" "github.com/klauspost/reedsolomon" ) @@ -26,10 +26,10 @@ type ( next uint32 // next seqid enc reedsolomon.Encoder shards [][]byte + shards2 [][]byte // for calcECC shardsflag []bool paws uint32 // Protect Against Wrapped Sequence numbers lastCheck uint32 - xmitBuf sync.Pool } fecPacket struct { @@ -60,11 +60,8 @@ func newFEC(rxlimit, dataShards, parityShards int) *FEC { } fec.enc = enc fec.shards = make([][]byte, fec.shardSize) + fec.shards2 = make([][]byte, fec.shardSize) fec.shardsflag = make([]bool, fec.shardSize) - fec.xmitBuf.New = func() interface{} { - return make([]byte, mtuLimit) - } - return fec } @@ -75,9 +72,8 @@ func (fec *FEC) decode(data []byte) fecPacket { pkt.flag = binary.LittleEndian.Uint16(data[4:]) pkt.ts = currentMs() // allocate memory & copy - buf := fec.xmitBuf.Get().([]byte) - n := copy(buf, data[6:]) - xorBytes(buf[n:], buf[n:], buf[n:]) + buf := xmitBuf.Get().([]byte)[:len(data)-6] + copy(buf, data[6:]) pkt.data = buf return pkt } @@ -107,7 +103,7 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) { if now-fec.rx[k].ts < fecExpire { rx = append(rx, fec.rx[k]) } else { - fec.xmitBuf.Put(fec.rx[k].data) + xmitBuf.Put(fec.rx[k].data) } } fec.rx = rx @@ -119,7 +115,7 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) { insertIdx := 0 for i := n; i >= 0; i-- { if pkt.seqid == fec.rx[i].seqid { // de-duplicate - fec.xmitBuf.Put(pkt.data) + xmitBuf.Put(pkt.data) return nil } else if pkt.seqid > fec.rx[i].seqid { // insertion insertIdx = i + 1 @@ -184,7 +180,7 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) { if numDataShard == fec.dataShards { // no lost for i := first; i < first+numshard; i++ { // free - fec.xmitBuf.Put(fec.rx[i].data) + xmitBuf.Put(fec.rx[i].data) } copy(fec.rx[first:], fec.rx[first+numshard:]) for i := 0; i < numshard; i++ { // dereference @@ -194,7 +190,9 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) { } 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 { @@ -206,7 +204,7 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) { } for i := first; i < first+numshard; i++ { // free - fec.xmitBuf.Put(fec.rx[i].data) + xmitBuf.Put(fec.rx[i].data) } copy(fec.rx[first:], fec.rx[first+numshard:]) for i := 0; i < numshard; i++ { // dereference @@ -218,7 +216,10 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) { // keep rxlimit if len(fec.rx) > fec.rxlimit { - fec.xmitBuf.Put(fec.rx[0].data) // free + if fec.rx[0].flag == typeData { // record unrecoverable data + atomic.AddUint64(&DefaultSnmp.FECShortShards, 1) + } + xmitBuf.Put(fec.rx[0].data) // free fec.rx[0].data = nil fec.rx = fec.rx[1:] } @@ -229,7 +230,7 @@ func (fec *FEC) calcECC(data [][]byte, offset, maxlen int) (ecc [][]byte) { if len(data) != fec.shardSize { return nil } - shards := make([][]byte, fec.shardSize) + shards := fec.shards2 for k := range shards { shards[k] = data[k][offset:maxlen] } diff --git a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/frame.png b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/frame.png index 7952e4a703e41ebdb1495fbd87a92ee096702556..0b0aefd4bb8ee90eebc068e507bd78329ab3d867 100644 GIT binary patch literal 36006 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 literal 8179 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 U{U66TP>-jo^jxu6-q`Q|0baRXv;Y7A diff --git a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp-go.png b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp-go.png new file mode 100644 index 0000000000000000000000000000000000000000..151b7c4f7c49c1a8382552322787a3e7f04ac3c6 GIT binary patch literal 9153 zcmdUzMOPe5(?HR|H88ll1b5fq65QP-xZB|F?m>dP1P=oQx4~UQa0~9dJiG5Ne2ebe zrx#VVsB^0OMyo2zpdk|?LqS2I$;nEoeQ@MsnIQr`cHFHzAQTiTj;*Ams+^=GxvHy^ zm92v%6qIaqx;BE2`Y5nKUkwrIGbS`ckyokqks)RhI*$Z4c^VXw_+SDHW4q^9XrfM- z;%z-BT_#UUtcE27N=Bv=GiVe>CpEF9rC(mZoX%hP-KMhNCxpE?U_r%bOuW1(nlR+K zg{)D?SC+KYwCr*lAef2xsmCQ}LpkJ2NH^6HjZ zS=_Ki~j=B@q`W;!B2A}>R%92w1dBq zzek*7$m!&PWS_UK!y`v`YZMP6;&w<3OvP@plo(mr;LLPv4`=#svb-5oZv3HHS%}Tx zqXfgUXNowshQp5ncg%TUzNTe0Q~bVAgAe|yMx-dL&zFH`HEAWcAJPi)IVc~7QwV5; zt7D^Zh=YwhAtV0_a%q3jA>c*T%5+MbXyfB$QnN}t+qQz2mRlkaq-KsHy*?X@gr_w` zIF$p~%a=OT?X16y;4|!}5%GGzuPT87pe;KEZE?YDdGjqmR}U=`W5 zU1uJsIM}Eg4J{R9#>Spx!!s3%rfc0t3)LM|f)Xx_XGOQ)Pd2`zFVxQ|LAQgn11!pQ z#`qmvok51dxznmSw4d*dt2y1joKxk27XPT&AC{Bas`T0b7958SH7Lbxju)iYyiq*|sq zW%h&@4CaQW^(3?(T5U)*6EZ?lp-E@s(N7E0r;QsRYHqA-K5Bb>8CYjtdD*?i-gi6L zj}-;<=B@j{80qXww$YgHJ)rVVO=98T)$+Xs0dNnAMTot~Xy0K`K@1ba=zP##+h{Og z98734G0H4>Z6Oj1$tgE5Oal&1s9FQM1K_U--7>5lSlk((EBMnkb30;PFuF5}5XfT& z!6-zW4fP8q90dheSb`0CXB3uM@G=EU6dg7wjN+>-WlCHrg}+o7vsebjj}bsA@k;zW zWiRD$a`Omo>8Fm!8}io?qPe5=viAeyvoFzU}lv?nzdxuQ8^2djwpjKn<^sG=aiy!i6ac71fw0J(jzW=`=hn# zYfMX&UWRol-@=L&*^9hY&FBfzex%i=`HsPlNsj6J`1l0)Xg}Is2|dzW>HozTHO{z5 zewWoO%29u<;H;oLCbZ+eMZG1x{T%;=v&?5M#pbbvyG3u6f7N^y0lqV&RU!&T#<~?6hhp3bc<_z3&_K7D+a`3niXseXn3r7lcIR0J!e%7nV z=+H`A^sg1xbJUYu6<8Ht?O0uFnYP6^WOMKK;BeMilF7MArips}??7dsQ0y5nKLbudTj7^w`d<>Js`Nz7V9k8ZMD78BiO!ME(WeFK z0XezUMU_sjqw4q)rHo0VT!f#DKh+ rPWxmb2Fy&lpd?t7ZrM6=*p4DcCmHBREt%LHs&& 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 literal 0 HcmV?d00001 diff --git a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp.go b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp.go index 78ccf26..f53e834 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp.go +++ b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp.go @@ -2,7 +2,6 @@ package kcp import ( - "container/heap" "encoding/binary" "sync/atomic" ) @@ -123,13 +122,6 @@ func (seg *Segment) encode(ptr []byte) []byte { return ptr } -// NewSegment creates a KCP segment -func NewSegment(size int) *Segment { - seg := new(Segment) - seg.data = make([]byte, size) - return seg -} - // KCP defines a single KCP connection type KCP struct { conv, mtu, mss, state uint32 @@ -137,7 +129,7 @@ type KCP struct { 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 + interval, ts_flush, xmit uint32 nodelay, updated uint32 ts_probe, probe_wait uint32 dead_link, incr uint32 @@ -150,33 +142,17 @@ type KCP struct { snd_buf []Segment rcv_buf []Segment - acklist ACKList + acklist []ackItem buffer []byte output Output } -// ACK packet to return -type ACK struct { +type ackItem struct { sn uint32 ts uint32 } -// ACKList is heapified -type ACKList []ACK - -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.(ACK)) } -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 { @@ -198,6 +174,18 @@ func NewKCP(conv uint32, output Output) *KCP { 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 { @@ -251,7 +239,7 @@ func (kcp *KCP) Recv(buffer []byte) (n int) { buffer = buffer[len(seg.data):] n += len(seg.data) count++ - seg.data = nil + kcp.delSegment(seg) if seg.frg == 0 { break } @@ -263,14 +251,13 @@ func (kcp *KCP) Recv(buffer []byte) (n int) { 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_queue = append(kcp.rcv_queue, *seg) kcp.rcv_nxt++ count++ - seg.data = nil } else { break } } + kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...) kcp.rcv_buf = kcp.rcv_buf[count:] // fast recover @@ -300,11 +287,12 @@ func (kcp *KCP) Send(buffer []byte) int { if len(buffer) < capacity { extend = len(buffer) } - seg := NewSegment(len(old.data) + extend) + seg := kcp.newSegment(len(old.data) + extend) seg.frg = 0 copy(seg.data, old.data) copy(seg.data[len(old.data):], buffer) buffer = buffer[extend:] + kcp.delSegment(old) kcp.snd_queue[n-1] = *seg } } @@ -335,7 +323,7 @@ func (kcp *KCP) Send(buffer []byte) int { } else { size = len(buffer) } - seg := NewSegment(size) + seg := kcp.newSegment(size) copy(seg.data, buffer[:size]) if kcp.stream == 0 { // message mode seg.frg = uint32(count - i - 1) @@ -348,8 +336,8 @@ func (kcp *KCP) Send(buffer []byte) int { return 0 } -// https://tools.ietf.org/html/rfc6298 func (kcp *KCP) update_ack(rtt int32) { + // https://tools.ietf.org/html/rfc6298 var rto uint32 if kcp.rx_srtt == 0 { kcp.rx_srtt = uint32(rtt) @@ -365,7 +353,7 @@ func (kcp *KCP) update_ack(rtt int32) { kcp.rx_srtt = 1 } } - rto = kcp.rx_srtt + _imax_(1, 4*kcp.rx_rttval) + rto = kcp.rx_srtt + _imax_(kcp.interval, 4*kcp.rx_rttval) kcp.rx_rto = _ibound_(kcp.rx_minrto, rto, IKCP_RTO_MAX) } @@ -386,6 +374,7 @@ func (kcp *KCP) parse_ack(sn uint32) { for k := range kcp.snd_buf { seg := &kcp.snd_buf[k] if sn == seg.sn { + kcp.delSegment(seg) copy(kcp.snd_buf[k:], kcp.snd_buf[k+1:]) kcp.snd_buf[len(kcp.snd_buf)-1] = Segment{} kcp.snd_buf = kcp.snd_buf[:len(kcp.snd_buf)-1] @@ -417,8 +406,8 @@ func (kcp *KCP) parse_una(una uint32) { for k := range kcp.snd_buf { seg := &kcp.snd_buf[k] if _itimediff(una, seg.sn) > 0 { + kcp.delSegment(seg) count++ - seg.data = nil } else { break } @@ -428,14 +417,14 @@ func (kcp *KCP) parse_una(una uint32) { // ack append func (kcp *KCP) ack_push(sn, ts uint32) { - heap.Push(&kcp.acklist, ACK{sn, ts}) + kcp.acklist = append(kcp.acklist, ackItem{sn, ts}) } func (kcp *KCP) parse_data(newseg *Segment) { sn := newseg.sn if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) >= 0 || _itimediff(sn, kcp.rcv_nxt) < 0 { - atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1) + kcp.delSegment(newseg) return } @@ -463,6 +452,8 @@ func (kcp *KCP) parse_data(newseg *Segment) { copy(kcp.rcv_buf[insert_idx+1:], kcp.rcv_buf[insert_idx:]) kcp.rcv_buf[insert_idx] = *newseg } + } else { + kcp.delSegment(newseg) } // move available data from rcv_buf -> rcv_queue @@ -470,14 +461,13 @@ func (kcp *KCP) parse_data(newseg *Segment) { 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_queue = append(kcp.rcv_queue, kcp.rcv_buf[k]) kcp.rcv_nxt++ count++ - seg.data = nil } else { break } } + kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...) kcp.rcv_buf = kcp.rcv_buf[count:] } @@ -489,7 +479,9 @@ func (kcp *KCP) Input(data []byte, update_ack bool) int { } var maxack uint32 + var recentack uint32 var flag int + for { var ts, sn, length, una, conv uint32 var wnd uint16 @@ -525,9 +517,6 @@ func (kcp *KCP) Input(data []byte, update_ack bool) int { kcp.shrink_buf() if cmd == IKCP_CMD_ACK { - if update_ack && _itimediff(kcp.current, ts) >= 0 { - kcp.update_ack(_itimediff(kcp.current, ts)) - } kcp.parse_ack(sn) kcp.shrink_buf() if flag == 0 { @@ -536,11 +525,12 @@ func (kcp *KCP) Input(data []byte, update_ack bool) int { } else if _itimediff(sn, maxack) > 0 { maxack = sn } + recentack = ts } else if cmd == IKCP_CMD_PUSH { if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) < 0 { kcp.ack_push(sn, ts) if _itimediff(sn, kcp.rcv_nxt) >= 0 { - seg := NewSegment(int(length)) + seg := kcp.newSegment(int(length)) seg.conv = conv seg.cmd = uint32(cmd) seg.frg = uint32(frg) @@ -550,7 +540,11 @@ func (kcp *KCP) Input(data []byte, update_ack bool) int { seg.una = una copy(seg.data, data[:length]) kcp.parse_data(seg) + } else { + atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1) } + } else { + atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1) } } else if cmd == IKCP_CMD_WASK { // ready to send back IKCP_CMD_WINS in Ikcp_flush @@ -565,8 +559,12 @@ func (kcp *KCP) Input(data []byte, update_ack bool) int { data = data[length:] } + current := currentMs() if flag != 0 && update_ack { kcp.parse_fastack(maxack) + if _itimediff(current, recentack) >= 0 { + kcp.update_ack(_itimediff(current, recentack)) + } } if _itimediff(kcp.snd_una, una) > 0 { @@ -603,14 +601,10 @@ func (kcp *KCP) wnd_unused() int32 { // flush pending data func (kcp *KCP) flush() { - current := kcp.current buffer := kcp.buffer change := 0 lost := false - if kcp.updated == 0 { - return - } var seg Segment seg.conv = kcp.conv seg.cmd = IKCP_CMD_ACK @@ -619,25 +613,28 @@ func (kcp *KCP) flush() { // flush acknowledges ptr := buffer - for kcp.acklist.Len() > 0 { + for i, ack := range kcp.acklist { size := len(buffer) - len(ptr) if size+IKCP_OVERHEAD > int(kcp.mtu) { kcp.output(buffer, size) ptr = buffer } - ack := heap.Pop(&kcp.acklist).(ACK) - seg.sn, seg.ts = ack.sn, ack.ts - ptr = seg.encode(ptr) + // filter jitters caused by bufferbloat + if ack.sn >= kcp.rcv_nxt || len(kcp.acklist)-1 == i { + seg.sn, seg.ts = ack.sn, ack.ts + ptr = seg.encode(ptr) + } } kcp.acklist = nil + current := currentMs() // probe window size (if remote window size equals zero) if kcp.rmt_wnd == 0 { if kcp.probe_wait == 0 { kcp.probe_wait = IKCP_PROBE_INIT - kcp.ts_probe = kcp.current + kcp.probe_wait + kcp.ts_probe = current + kcp.probe_wait } else { - if _itimediff(kcp.current, kcp.ts_probe) >= 0 { + if _itimediff(current, kcp.ts_probe) >= 0 { if kcp.probe_wait < IKCP_PROBE_INIT { kcp.probe_wait = IKCP_PROBE_INIT } @@ -645,7 +642,7 @@ func (kcp *KCP) flush() { if kcp.probe_wait > IKCP_PROBE_LIMIT { kcp.probe_wait = IKCP_PROBE_LIMIT } - kcp.ts_probe = kcp.current + kcp.probe_wait + kcp.ts_probe = current + kcp.probe_wait kcp.probe |= IKCP_ASK_SEND } } @@ -684,6 +681,7 @@ func (kcp *KCP) flush() { cwnd = _imin_(kcp.cwnd, cwnd) } + // sliding window, controlled by snd_nxt && sna_una+cwnd count := 0 for k := range kcp.snd_queue { if _itimediff(kcp.snd_nxt, kcp.snd_una+cwnd) >= 0 { @@ -696,10 +694,8 @@ func (kcp *KCP) flush() { newseg.ts = current newseg.sn = kcp.snd_nxt newseg.una = kcp.rcv_nxt - newseg.resendts = current + newseg.resendts = newseg.ts newseg.rto = kcp.rx_rto - newseg.fastack = 0 - newseg.xmit = 0 kcp.snd_buf = append(kcp.snd_buf, newseg) kcp.snd_nxt++ count++ @@ -707,27 +703,29 @@ func (kcp *KCP) flush() { } kcp.snd_queue = kcp.snd_queue[count:] + // flag pending data + hasPending := false + if count > 0 { + hasPending = true + } + // calculate resent resent := uint32(kcp.fastresend) if kcp.fastresend <= 0 { resent = 0xffffffff } - rtomin := (kcp.rx_rto >> 3) - if kcp.nodelay != 0 { - rtomin = 0 - } // flush data segments - nque := len(kcp.snd_queue) var lostSegs, fastRetransSegs, earlyRetransSegs uint64 for k := range kcp.snd_buf { + current := currentMs() segment := &kcp.snd_buf[k] needsend := false if segment.xmit == 0 { needsend = true segment.xmit++ segment.rto = kcp.rx_rto - segment.resendts = current + segment.rto + rtomin + segment.resendts = current + segment.rto } else if _itimediff(current, segment.resendts) >= 0 { needsend = true segment.xmit++ @@ -740,21 +738,26 @@ func (kcp *KCP) flush() { segment.resendts = current + segment.rto lost = true lostSegs++ - } else if segment.fastack >= resent { - needsend = true - segment.xmit++ - segment.fastack = 0 - segment.resendts = current + segment.rto - change++ - fastRetransSegs++ - } else if segment.fastack > 0 && nque == 0 { - // early retransmit - needsend = true - segment.xmit++ - segment.fastack = 0 - segment.resendts = current + segment.rto - change++ - earlyRetransSegs++ + } else if segment.fastack >= resent { // fast retransmit + lastsend := segment.resendts - segment.rto + if _itimediff(current, lastsend) >= int32(kcp.rx_rto/4) { + needsend = true + segment.xmit++ + segment.fastack = 0 + segment.resendts = current + segment.rto + change++ + fastRetransSegs++ + } + } else if segment.fastack > 0 && !hasPending { // early retransmit + lastsend := segment.resendts - segment.rto + if _itimediff(current, lastsend) >= int32(kcp.rx_rto/4) { + needsend = true + segment.xmit++ + segment.fastack = 0 + segment.resendts = current + segment.rto + change++ + earlyRetransSegs++ + } } if needsend { @@ -822,27 +825,26 @@ func (kcp *KCP) flush() { // Update updates state (call it repeatedly, every 10ms-100ms), or you can ask // ikcp_check when to call it again (without ikcp_input/_send calling). // 'current' - current timestamp in millisec. -func (kcp *KCP) Update(current uint32) { +func (kcp *KCP) Update() { var slap int32 - kcp.current = current - + current := currentMs() if kcp.updated == 0 { kcp.updated = 1 - kcp.ts_flush = kcp.current + kcp.ts_flush = current } - slap = _itimediff(kcp.current, kcp.ts_flush) + slap = _itimediff(current, kcp.ts_flush) if slap >= 10000 || slap < -10000 { - kcp.ts_flush = kcp.current + kcp.ts_flush = current slap = 0 } if slap >= 0 { kcp.ts_flush += kcp.interval - if _itimediff(kcp.current, kcp.ts_flush) >= 0 { - kcp.ts_flush = kcp.current + kcp.interval + if _itimediff(current, kcp.ts_flush) >= 0 { + kcp.ts_flush = current + kcp.interval } kcp.flush() } @@ -855,7 +857,8 @@ func (kcp *KCP) Update(current uint32) { // Important to reduce unnacessary ikcp_update invoking. use it to // schedule ikcp_update (eg. implementing an epoll-like mechanism, // or optimize ikcp_update when handling massive kcp connections) -func (kcp *KCP) Check(current uint32) uint32 { +func (kcp *KCP) Check() uint32 { + current := currentMs() ts_flush := kcp.ts_flush tm_flush := int32(0x7fffffff) tm_packet := int32(0x7fffffff) diff --git a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/sess.go b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/sess.go index 737b99d..4879e2a 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/sess.go +++ b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/sess.go @@ -3,6 +3,7 @@ package kcp import ( "crypto/rand" "encoding/binary" + "hash/crc32" "io" "net" "sync" @@ -10,20 +11,9 @@ import ( "time" "github.com/pkg/errors" - - "github.com/klauspost/crc32" - "golang.org/x/net/ipv4" ) -// Option defines extra options -type Option interface{} - -// OptionWithConvId defines conversation id -type OptionWithConvId struct { - Id uint32 -} - type errTimeout struct { error } @@ -38,11 +28,26 @@ const ( crcSize = 4 // 4bytes packet checksum cryptHeaderSize = nonceSize + crcSize mtuLimit = 2048 - txQueueLimit = 8192 - rxFecLimit = 8192 - defaultKeepAliveInterval = 10 * time.Second + rxQueueLimit = 8192 + rxFECMulti = 3 // FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory + defaultKeepAliveInterval = 10 ) +const ( + errBrokenPipe = "broken pipe" + errInvalidOperation = "invalid operation" +) + +var ( + xmitBuf sync.Pool +) + +func init() { + xmitBuf.New = func() interface{} { + return make([]byte, mtuLimit) + } +} + type ( // UDPSession defines a KCP session implemented by UDP UDPSession struct { @@ -58,14 +63,13 @@ type ( die chan struct{} chReadEvent chan struct{} chWriteEvent chan struct{} - chTicker chan time.Time chUDPOutput chan []byte headerSize int ackNoDelay bool isClosed bool - keepAliveInterval time.Duration - xmitBuf sync.Pool + keepAliveInterval int32 mu sync.Mutex + updateInterval int32 } setReadBuffer interface { @@ -80,8 +84,7 @@ type ( // newUDPSession create a new udp session for client or server func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn net.PacketConn, remote net.Addr, block BlockCrypt) *UDPSession { sess := new(UDPSession) - sess.chTicker = make(chan time.Time, 1) - sess.chUDPOutput = make(chan []byte, txQueueLimit) + sess.chUDPOutput = make(chan []byte) sess.die = make(chan struct{}) sess.chReadEvent = make(chan struct{}, 1) sess.chWriteEvent = make(chan struct{}, 1) @@ -90,10 +93,7 @@ func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn sess.keepAliveInterval = defaultKeepAliveInterval sess.l = l sess.block = block - sess.fec = newFEC(rxFecLimit, dataShards, parityShards) - sess.xmitBuf.New = func() interface{} { - return make([]byte, mtuLimit) - } + sess.fec = newFEC(rxFECMulti*(dataShards+parityShards), dataShards, parityShards) // calculate header size if sess.block != nil { sess.headerSize += cryptHeaderSize @@ -104,7 +104,7 @@ func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn sess.kcp = NewKCP(conv, func(buf []byte, size int) { if size >= IKCP_OVERHEAD { - ext := sess.xmitBuf.Get().([]byte)[:sess.headerSize+size] + ext := xmitBuf.Get().([]byte)[:sess.headerSize+size] copy(ext[sess.headerSize:], buf) select { case sess.chUDPOutput <- ext: @@ -145,7 +145,7 @@ func (s *UDPSession) Read(b []byte) (n int, err error) { if s.isClosed { s.mu.Unlock() - return 0, errors.New("broken pipe") + return 0, errors.New(errBrokenPipe) } if !s.rd.IsZero() { @@ -169,19 +169,25 @@ func (s *UDPSession) Read(b []byte) (n int, err error) { return n, nil } - var timeout <-chan time.Time + var timeout *time.Timer + var c <-chan time.Time if !s.rd.IsZero() { delay := s.rd.Sub(time.Now()) - timeout = time.After(delay) + timeout = time.NewTimer(delay) + c = timeout.C } s.mu.Unlock() // wait for read event or timeout select { case <-s.chReadEvent: - case <-timeout: + case <-c: case <-s.die: } + + if timeout != nil { + timeout.Stop() + } } } @@ -191,7 +197,7 @@ func (s *UDPSession) Write(b []byte) (n int, err error) { s.mu.Lock() if s.isClosed { s.mu.Unlock() - return 0, errors.New("broken pipe") + return 0, errors.New(errBrokenPipe) } if !s.wd.IsZero() { @@ -201,7 +207,7 @@ func (s *UDPSession) Write(b []byte) (n int, err error) { } } - if s.kcp.WaitSnd() < 2*int(s.kcp.snd_wnd) { + if s.kcp.WaitSnd() < int(s.kcp.snd_wnd) { n = len(b) max := s.kcp.mss << 8 for { @@ -213,26 +219,31 @@ func (s *UDPSession) Write(b []byte) (n int, err error) { b = b[max:] } } - s.kcp.current = currentMs() s.kcp.flush() s.mu.Unlock() atomic.AddUint64(&DefaultSnmp.BytesSent, uint64(n)) return n, nil } - var timeout <-chan time.Time + var timeout *time.Timer + var c <-chan time.Time if !s.wd.IsZero() { delay := s.wd.Sub(time.Now()) - timeout = time.After(delay) + timeout = time.NewTimer(delay) + c = timeout.C } s.mu.Unlock() // wait for write event or timeout select { case <-s.chWriteEvent: - case <-timeout: + case <-c: case <-s.die: } + + if timeout != nil { + timeout.Stop() + } } } @@ -241,7 +252,7 @@ func (s *UDPSession) Close() error { s.mu.Lock() defer s.mu.Unlock() if s.isClosed { - return errors.New("broken pipe") + return errors.New(errBrokenPipe) } close(s.die) s.isClosed = true @@ -321,6 +332,7 @@ func (s *UDPSession) SetNoDelay(nodelay, interval, resend, nc int) { s.mu.Lock() defer s.mu.Unlock() s.kcp.NoDelay(nodelay, interval, resend, nc) + atomic.StoreInt32(&s.updateInterval, int32(interval)) } // SetDSCP sets the 6bit DSCP field of IP header, no effect if it's accepted from Listener @@ -328,11 +340,13 @@ func (s *UDPSession) SetDSCP(dscp int) error { s.mu.Lock() defer s.mu.Unlock() if s.l == nil { - if nc, ok := s.conn.(net.Conn); ok { + if nc, ok := s.conn.(*ConnectedUDPConn); ok { + return ipv4.NewConn(nc.Conn).SetTOS(dscp << 2) + } else if nc, ok := s.conn.(net.Conn); ok { return ipv4.NewConn(nc).SetTOS(dscp << 2) } } - return nil + return errors.New(errInvalidOperation) } // SetReadBuffer sets the socket read buffer, no effect if it's accepted from Listener @@ -344,7 +358,7 @@ func (s *UDPSession) SetReadBuffer(bytes int) error { return nc.SetReadBuffer(bytes) } } - return nil + return errors.New(errInvalidOperation) } // SetWriteBuffer sets the socket write buffer, no effect if it's accepted from Listener @@ -356,24 +370,12 @@ func (s *UDPSession) SetWriteBuffer(bytes int) error { return nc.SetWriteBuffer(bytes) } } - return nil + return errors.New(errInvalidOperation) } // SetKeepAlive changes per-connection NAT keepalive interval; 0 to disable, default to 10s func (s *UDPSession) SetKeepAlive(interval int) { - s.mu.Lock() - defer s.mu.Unlock() - s.keepAliveInterval = time.Duration(interval) * time.Second -} - -// writeTo wraps write method for client & listener -func (s *UDPSession) writeTo(b []byte, addr net.Addr) (int, error) { - if s.l == nil { - if nc, ok := s.conn.(io.Writer); ok { - return nc.Write(b) - } - } - return s.conn.WriteTo(b, addr) + atomic.StoreInt32(&s.keepAliveInterval, int32(interval)) } func (s *UDPSession) outputTask() { @@ -385,13 +387,15 @@ func (s *UDPSession) outputTask() { szOffset := fecOffset + fecHeaderSize // fec data group + var cacheLine []byte var fecGroup [][]byte var fecCnt int var fecMaxSize int if s.fec != nil { + cacheLine = make([]byte, s.fec.shardSize*mtuLimit) fecGroup = make([][]byte, s.fec.shardSize) for k := range fecGroup { - fecGroup[k] = make([]byte, mtuLimit) + fecGroup[k] = cacheLine[k*mtuLimit : (k+1)*mtuLimit] } } @@ -402,23 +406,31 @@ func (s *UDPSession) outputTask() { for { select { + // receive from a synchronous channel + // buffered channel must be avoided, because of "bufferbloat" case ext := <-s.chUDPOutput: var ecc [][]byte if s.fec != nil { s.fec.markData(ext[fecOffset:]) - // explicit size + // explicit size, including 2bytes size itself. binary.LittleEndian.PutUint16(ext[szOffset:], uint16(len(ext[szOffset:]))) // copy data to fec group - xorBytes(fecGroup[fecCnt], fecGroup[fecCnt], fecGroup[fecCnt]) + sz := len(ext) + fecGroup[fecCnt] = fecGroup[fecCnt][:sz] copy(fecGroup[fecCnt], ext) fecCnt++ - if len(ext) > fecMaxSize { - fecMaxSize = len(ext) + if sz > fecMaxSize { + fecMaxSize = sz } // calculate Reed-Solomon Erasure Code if fecCnt == s.fec.dataShards { + for i := 0; i < s.fec.dataShards; i++ { + shard := fecGroup[i] + slen := len(shard) + xorBytes(shard[slen:fecMaxSize], shard[slen:fecMaxSize], shard[slen:fecMaxSize]) + } ecc = s.fec.calcECC(fecGroup, szOffset, fecMaxSize) for k := range ecc { s.fec.markFEC(ecc[k][fecOffset:]) @@ -445,38 +457,36 @@ func (s *UDPSession) outputTask() { } } - //if rand.Intn(100) < 80 { - if n, err := s.writeTo(ext, s.remote); err == nil { - atomic.AddUint64(&DefaultSnmp.OutSegs, 1) - atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(n)) + nbytes := 0 + nsegs := 0 + // if mrand.Intn(100) < 50 { + if n, err := s.conn.WriteTo(ext, s.remote); err == nil { + nbytes += n + nsegs++ } - //} + // } if ecc != nil { for k := range ecc { - if n, err := s.writeTo(ecc[k], s.remote); err == nil { - atomic.AddUint64(&DefaultSnmp.OutSegs, 1) - atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(n)) + if n, err := s.conn.WriteTo(ecc[k], s.remote); err == nil { + nbytes += n + nsegs++ } } } - xorBytes(ext, ext, ext) - s.xmitBuf.Put(ext) + atomic.AddUint64(&DefaultSnmp.OutSegs, uint64(nsegs)) + atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(nbytes)) + xmitBuf.Put(ext) case <-ticker.C: // NAT keep-alive - if len(s.chUDPOutput) == 0 { - s.mu.Lock() - interval := s.keepAliveInterval - s.mu.Unlock() - if interval > 0 && time.Now().After(lastPing.Add(interval)) { - buf := make([]byte, 2) - io.ReadFull(rand.Reader, buf) - rnd := int(binary.LittleEndian.Uint16(buf)) - sz := rnd%(IKCP_MTU_DEF-s.headerSize-IKCP_OVERHEAD) + s.headerSize + IKCP_OVERHEAD - ping := make([]byte, sz) - io.ReadFull(rand.Reader, ping) - s.writeTo(ping, s.remote) - lastPing = time.Now() - } + interval := time.Duration(atomic.LoadInt32(&s.keepAliveInterval)) * time.Second + if interval > 0 && time.Now().After(lastPing.Add(interval)) { + var rnd uint16 + binary.Read(rand.Reader, binary.LittleEndian, &rnd) + sz := int(rnd)%(IKCP_MTU_DEF-s.headerSize-IKCP_OVERHEAD) + s.headerSize + IKCP_OVERHEAD + ping := make([]byte, sz) // randomized ping packet + io.ReadFull(rand.Reader, ping) + s.conn.WriteTo(ping, s.remote) + lastPing = time.Now() } case <-s.die: return @@ -486,25 +496,18 @@ func (s *UDPSession) outputTask() { // kcp update, input loop func (s *UDPSession) updateTask() { - var tc <-chan time.Time - if s.l == nil { // client - ticker := time.NewTicker(10 * time.Millisecond) - tc = ticker.C - defer ticker.Stop() - } else { - tc = s.chTicker - } + tc := time.After(time.Duration(atomic.LoadInt32(&s.updateInterval)) * time.Millisecond) for { select { case <-tc: s.mu.Lock() - current := currentMs() - s.kcp.Update(current) - if s.kcp.WaitSnd() < 2*int(s.kcp.snd_wnd) { + s.kcp.flush() + if s.kcp.WaitSnd() < int(s.kcp.snd_wnd) { s.notifyWriteEvent() } s.mu.Unlock() + tc = time.After(time.Duration(atomic.LoadInt32(&s.updateInterval)) * time.Millisecond) case <-s.die: if s.l != nil { // has listener select { @@ -537,58 +540,84 @@ func (s *UDPSession) notifyWriteEvent() { } func (s *UDPSession) kcpInput(data []byte) { - current := currentMs() + var kcpInErrors, fecErrs, fecRecovered, fecSegs uint64 + if s.fec != nil { f := s.fec.decode(data) + s.mu.Lock() + if f.flag == typeData { + if ret := s.kcp.Input(data[fecHeaderSizePlus2:], true); ret != 0 { + kcpInErrors++ + } + } + if f.flag == typeData || f.flag == typeFEC { if f.flag == typeFEC { - atomic.AddUint64(&DefaultSnmp.FECSegs, 1) + fecSegs++ } if recovers := s.fec.input(f); recovers != nil { - s.mu.Lock() - s.kcp.current = current - for k := range recovers { - sz := binary.LittleEndian.Uint16(recovers[k]) - if int(sz) <= len(recovers[k]) && sz >= 2 { - s.kcp.Input(recovers[k][2:sz], false) + for _, r := range recovers { + if len(r) >= 2 { // must be larger than 2bytes + sz := binary.LittleEndian.Uint16(r) + if int(sz) <= len(r) && sz >= 2 { + if ret := s.kcp.Input(r[2:sz], false); ret == 0 { + fecRecovered++ + } else { + kcpInErrors++ + } + } else { + fecErrs++ + } } else { - atomic.AddUint64(&DefaultSnmp.FECErrs, 1) + fecErrs++ } } - s.mu.Unlock() - atomic.AddUint64(&DefaultSnmp.FECRecovered, uint64(len(recovers))) } } - if f.flag == typeData { - s.mu.Lock() - s.kcp.current = current - s.kcp.Input(data[fecHeaderSizePlus2:], true) - s.mu.Unlock() + + // notify reader + if n := s.kcp.PeekSize(); n > 0 { + s.notifyReadEvent() } + if s.ackNoDelay { + s.kcp.flush() + } + s.mu.Unlock() } else { s.mu.Lock() - s.kcp.current = current - s.kcp.Input(data, true) + if ret := s.kcp.Input(data, true); ret != 0 { + kcpInErrors++ + } + // notify reader + if n := s.kcp.PeekSize(); n > 0 { + s.notifyReadEvent() + } + if s.ackNoDelay { + s.kcp.flush() + } s.mu.Unlock() } - // notify reader - s.mu.Lock() - if n := s.kcp.PeekSize(); n > 0 { - s.notifyReadEvent() - } - if s.ackNoDelay { - s.kcp.current = current - s.kcp.flush() - } - s.mu.Unlock() atomic.AddUint64(&DefaultSnmp.InSegs, 1) + atomic.AddUint64(&DefaultSnmp.InBytes, uint64(len(data))) + if fecSegs > 0 { + atomic.AddUint64(&DefaultSnmp.FECSegs, fecSegs) + } + if kcpInErrors > 0 { + atomic.AddUint64(&DefaultSnmp.KCPInErrors, kcpInErrors) + } + if fecErrs > 0 { + atomic.AddUint64(&DefaultSnmp.FECErrs, fecErrs) + } + if fecRecovered > 0 { + atomic.AddUint64(&DefaultSnmp.FECRecovered, fecRecovered) + } } func (s *UDPSession) receiver(ch chan []byte) { for { - data := s.xmitBuf.Get().([]byte)[:mtuLimit] + data := xmitBuf.Get().([]byte)[:mtuLimit] if n, _, err := s.conn.ReadFrom(data); err == nil && n >= s.headerSize+IKCP_OVERHEAD { select { case ch <- data[:n]: @@ -604,7 +633,7 @@ func (s *UDPSession) receiver(ch chan []byte) { // read loop for client session func (s *UDPSession) readLoop() { - chPacket := make(chan []byte, txQueueLimit) + chPacket := make(chan []byte, rxQueueLimit) go s.receiver(chPacket) for { @@ -629,8 +658,7 @@ func (s *UDPSession) readLoop() { if dataValid { s.kcpInput(data) } - xorBytes(raw, raw, raw) - s.xmitBuf.Put(raw) + xmitBuf.Put(raw) case <-s.die: return } @@ -662,10 +690,8 @@ type ( // monitor incoming data for all connections of server func (l *Listener) monitor() { - chPacket := make(chan packet, txQueueLimit) + chPacket := make(chan packet, rxQueueLimit) go l.receiver(chPacket) - ticker := time.NewTicker(10 * time.Millisecond) - defer ticker.Stop() for { select { case p := <-chPacket: @@ -715,20 +741,11 @@ func (l *Listener) monitor() { } } - xorBytes(raw, raw, raw) l.rxbuf.Put(raw) case deadlink := <-l.chDeadlinks: delete(l.sessions, deadlink.String()) case <-l.die: return - case <-ticker.C: - now := time.Now() - for _, s := range l.sessions { - select { - case s.chTicker <- now: - default: - } - } } } } @@ -751,7 +768,7 @@ func (l *Listener) SetReadBuffer(bytes int) error { if nc, ok := l.conn.(setReadBuffer); ok { return nc.SetReadBuffer(bytes) } - return nil + return errors.New(errInvalidOperation) } // SetWriteBuffer sets the socket write buffer for the Listener @@ -759,7 +776,7 @@ func (l *Listener) SetWriteBuffer(bytes int) error { if nc, ok := l.conn.(setWriteBuffer); ok { return nc.SetWriteBuffer(bytes) } - return nil + return errors.New(errInvalidOperation) } // SetDSCP sets the 6bit DSCP field of IP header @@ -767,7 +784,7 @@ func (l *Listener) SetDSCP(dscp int) error { if nc, ok := l.conn.(net.Conn); ok { return ipv4.NewConn(nc).SetTOS(dscp << 2) } - return nil + return errors.New(errInvalidOperation) } // Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn. @@ -788,7 +805,7 @@ func (l *Listener) AcceptKCP() (*UDPSession, error) { case c := <-l.chAccepts: return c, nil case <-l.die: - return nil, errors.New("listener stopped") + return nil, errors.New(errBrokenPipe) } } @@ -823,7 +840,7 @@ func (l *Listener) Addr() net.Addr { } // Listen listens for incoming KCP packets addressed to the local address laddr on the network "udp", -func Listen(laddr string) (*Listener, error) { +func Listen(laddr string) (net.Listener, error) { return ListenWithOptions(laddr, nil, 0, 0) } @@ -839,6 +856,11 @@ func ListenWithOptions(laddr string, block BlockCrypt, dataShards, parityShards return nil, errors.Wrap(err, "net.ListenUDP") } + return ServeConn(block, dataShards, parityShards, conn) +} + +// ServeConn serves KCP protocol for a single packet connection. +func ServeConn(block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*Listener, error) { l := new(Listener) l.conn = conn l.sessions = make(map[string]*UDPSession) @@ -848,7 +870,7 @@ func ListenWithOptions(laddr string, block BlockCrypt, dataShards, parityShards l.dataShards = dataShards l.parityShards = parityShards l.block = block - l.fec = newFEC(rxFecLimit, dataShards, parityShards) + l.fec = newFEC(rxFECMulti*(dataShards+parityShards), dataShards, parityShards) l.rxbuf.New = func() interface{} { return make([]byte, mtuLimit) } @@ -866,12 +888,12 @@ func ListenWithOptions(laddr string, block BlockCrypt, dataShards, parityShards } // Dial connects to the remote address "raddr" on the network "udp" -func Dial(raddr string) (*UDPSession, error) { +func Dial(raddr string) (net.Conn, error) { return DialWithOptions(raddr, nil, 0, 0) } // DialWithOptions connects to the remote address "raddr" on the network "udp" with packet encryption -func DialWithOptions(raddr string, block BlockCrypt, dataShards, parityShards int, opts ...Option) (*UDPSession, error) { +func DialWithOptions(raddr string, block BlockCrypt, dataShards, parityShards int) (*UDPSession, error) { udpaddr, err := net.ResolveUDPAddr("udp", raddr) if err != nil { return nil, errors.Wrap(err, "net.ResolveUDPAddr") @@ -882,20 +904,34 @@ func DialWithOptions(raddr string, block BlockCrypt, dataShards, parityShards in return nil, errors.Wrap(err, "net.DialUDP") } - buf := make([]byte, 4) - io.ReadFull(rand.Reader, buf) - convid := binary.LittleEndian.Uint32(buf) - for k := range opts { - switch opt := opts[k].(type) { - case OptionWithConvId: - convid = opt.Id - default: - return nil, errors.New("unrecognized option") - } + return NewConn(raddr, block, dataShards, parityShards, &ConnectedUDPConn{udpconn, udpconn}) +} + +// NewConn establishes a session and talks KCP protocol over a packet connection. +func NewConn(raddr string, block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*UDPSession, error) { + udpaddr, err := net.ResolveUDPAddr("udp", raddr) + if err != nil { + return nil, errors.Wrap(err, "net.ResolveUDPAddr") } - return newUDPSession(convid, dataShards, parityShards, nil, udpconn, udpaddr, block), nil + + var convid uint32 + binary.Read(rand.Reader, binary.LittleEndian, &convid) + return newUDPSession(convid, dataShards, parityShards, nil, conn, udpaddr, block), nil } func currentMs() uint32 { return uint32(time.Now().UnixNano() / int64(time.Millisecond)) } + +// ConnectedUDPConn is a wrapper for net.UDPConn which converts WriteTo syscalls +// to Write syscalls that are 4 times faster on some OS'es. This should only be +// used for connections that were produced by a net.Dial* call. +type ConnectedUDPConn struct { + *net.UDPConn + Conn net.Conn // underlying connection if any +} + +// WriteTo redirects all writes to the Write syscall, which is 4 times faster. +func (c *ConnectedUDPConn) WriteTo(b []byte, addr net.Addr) (int, error) { + return c.Write(b) +} diff --git a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/snmp.go b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/snmp.go index 997b163..e8ab194 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/snmp.go +++ b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/snmp.go @@ -1,34 +1,95 @@ package kcp -import "sync/atomic" +import ( + "fmt" + "sync/atomic" +) // Snmp defines network statistics indicator type Snmp struct { - BytesSent uint64 // payload bytes sent + BytesSent uint64 // raw bytes sent BytesReceived uint64 MaxConn uint64 ActiveOpens uint64 PassiveOpens uint64 - CurrEstab uint64 - InErrs uint64 - InCsumErrors uint64 // checksum errors + CurrEstab uint64 // count of connections for now + InErrs uint64 // udp read errors + InCsumErrors uint64 // checksum errors from CRC32 + KCPInErrors uint64 // packet iput errors from kcp InSegs uint64 OutSegs uint64 + InBytes uint64 // udp bytes received OutBytes uint64 // udp bytes sent RetransSegs uint64 FastRetransSegs uint64 EarlyRetransSegs uint64 - LostSegs uint64 - RepeatSegs uint64 - FECRecovered uint64 - FECErrs uint64 - FECSegs uint64 // fec segments received + LostSegs uint64 // number of segs infered as lost + RepeatSegs uint64 // number of segs duplicated + FECRecovered uint64 // correct packets recovered from FEC + FECErrs uint64 // incorrect packets recovered from FEC + FECSegs uint64 // FEC segments received + FECShortShards uint64 // number of data shards that's not enough for recovery } func newSnmp() *Snmp { return new(Snmp) } +func (s *Snmp) Header() []string { + return []string{ + "BytesSent", + "BytesReceived", + "MaxConn", + "ActiveOpens", + "PassiveOpens", + "CurrEstab", + "InErrs", + "InCsumErrors", + "KCPInErrors", + "InSegs", + "OutSegs", + "InBytes", + "OutBytes", + "RetransSegs", + "FastRetransSegs", + "EarlyRetransSegs", + "LostSegs", + "RepeatSegs", + "FECSegs", + "FECErrs", + "FECRecovered", + "FECShortShards", + } +} + +func (s *Snmp) ToSlice() []string { + snmp := s.Copy() + return []string{ + fmt.Sprint(snmp.BytesSent), + fmt.Sprint(snmp.BytesReceived), + fmt.Sprint(snmp.MaxConn), + fmt.Sprint(snmp.ActiveOpens), + fmt.Sprint(snmp.PassiveOpens), + fmt.Sprint(snmp.CurrEstab), + fmt.Sprint(snmp.InErrs), + fmt.Sprint(snmp.InCsumErrors), + fmt.Sprint(snmp.KCPInErrors), + fmt.Sprint(snmp.InSegs), + fmt.Sprint(snmp.OutSegs), + fmt.Sprint(snmp.InBytes), + fmt.Sprint(snmp.OutBytes), + fmt.Sprint(snmp.RetransSegs), + fmt.Sprint(snmp.FastRetransSegs), + fmt.Sprint(snmp.EarlyRetransSegs), + fmt.Sprint(snmp.LostSegs), + fmt.Sprint(snmp.RepeatSegs), + fmt.Sprint(snmp.FECSegs), + fmt.Sprint(snmp.FECErrs), + fmt.Sprint(snmp.FECRecovered), + fmt.Sprint(snmp.FECShortShards), + } +} + // Copy make a copy of current snmp snapshot func (s *Snmp) Copy() *Snmp { d := newSnmp() @@ -40,8 +101,10 @@ func (s *Snmp) Copy() *Snmp { d.CurrEstab = atomic.LoadUint64(&s.CurrEstab) d.InErrs = atomic.LoadUint64(&s.InErrs) d.InCsumErrors = atomic.LoadUint64(&s.InCsumErrors) + d.KCPInErrors = atomic.LoadUint64(&s.KCPInErrors) d.InSegs = atomic.LoadUint64(&s.InSegs) d.OutSegs = atomic.LoadUint64(&s.OutSegs) + d.InBytes = atomic.LoadUint64(&s.InBytes) d.OutBytes = atomic.LoadUint64(&s.OutBytes) d.RetransSegs = atomic.LoadUint64(&s.RetransSegs) d.FastRetransSegs = atomic.LoadUint64(&s.FastRetransSegs) @@ -51,9 +114,36 @@ func (s *Snmp) Copy() *Snmp { d.FECSegs = atomic.LoadUint64(&s.FECSegs) d.FECErrs = atomic.LoadUint64(&s.FECErrs) d.FECRecovered = atomic.LoadUint64(&s.FECRecovered) + d.FECShortShards = atomic.LoadUint64(&s.FECShortShards) return d } +// Reset values to zero +func (s *Snmp) Reset() { + atomic.StoreUint64(&s.BytesSent, 0) + atomic.StoreUint64(&s.BytesReceived, 0) + atomic.StoreUint64(&s.MaxConn, 0) + atomic.StoreUint64(&s.ActiveOpens, 0) + atomic.StoreUint64(&s.PassiveOpens, 0) + atomic.StoreUint64(&s.CurrEstab, 0) + atomic.StoreUint64(&s.InErrs, 0) + atomic.StoreUint64(&s.InCsumErrors, 0) + atomic.StoreUint64(&s.KCPInErrors, 0) + atomic.StoreUint64(&s.InSegs, 0) + atomic.StoreUint64(&s.OutSegs, 0) + atomic.StoreUint64(&s.InBytes, 0) + atomic.StoreUint64(&s.OutBytes, 0) + atomic.StoreUint64(&s.RetransSegs, 0) + atomic.StoreUint64(&s.FastRetransSegs, 0) + atomic.StoreUint64(&s.EarlyRetransSegs, 0) + atomic.StoreUint64(&s.LostSegs, 0) + atomic.StoreUint64(&s.RepeatSegs, 0) + atomic.StoreUint64(&s.FECSegs, 0) + atomic.StoreUint64(&s.FECErrs, 0) + atomic.StoreUint64(&s.FECRecovered, 0) + atomic.StoreUint64(&s.FECShortShards, 0) +} + // DefaultSnmp is the global KCP connection statistics collector var DefaultSnmp *Snmp diff --git a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/xor.go b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/xor.go index 5d21095..20fa2e4 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/xor.go +++ b/cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/xor.go @@ -44,15 +44,18 @@ func safeXORBytes(dst, a, b []byte) int { } for i := ex; i < n; i += 8 { - dst[i] = a[i] ^ b[i] - dst[i+1] = a[i+1] ^ b[i+1] - dst[i+2] = a[i+2] ^ b[i+2] - dst[i+3] = a[i+3] ^ b[i+3] + _dst := dst[i : i+8] + _a := a[i : i+8] + _b := b[i : i+8] + _dst[0] = _a[0] ^ _b[0] + _dst[1] = _a[1] ^ _b[1] + _dst[2] = _a[2] ^ _b[2] + _dst[3] = _a[3] ^ _b[3] - dst[i+4] = a[i+4] ^ b[i+4] - dst[i+5] = a[i+5] ^ b[i+5] - dst[i+6] = a[i+6] ^ b[i+6] - dst[i+7] = a[i+7] ^ b[i+7] + _dst[4] = _a[4] ^ _b[4] + _dst[5] = _a[5] ^ _b[5] + _dst[6] = _a[6] ^ _b[6] + _dst[7] = _a[7] ^ _b[7] } return n } @@ -85,14 +88,17 @@ func fastXORWords(dst, a, b []byte) { } for i := ex; i < n; i += 8 { - dw[i] = aw[i] ^ bw[i] - dw[i+1] = aw[i+1] ^ bw[i+1] - dw[i+2] = aw[i+2] ^ bw[i+2] - dw[i+3] = aw[i+3] ^ bw[i+3] - dw[i+4] = aw[i+4] ^ bw[i+4] - dw[i+5] = aw[i+5] ^ bw[i+5] - dw[i+6] = aw[i+6] ^ bw[i+6] - dw[i+7] = aw[i+7] ^ bw[i+7] + _dw := dw[i : i+8] + _aw := aw[i : i+8] + _bw := bw[i : i+8] + _dw[0] = _aw[0] ^ _bw[0] + _dw[1] = _aw[1] ^ _bw[1] + _dw[2] = _aw[2] ^ _bw[2] + _dw[3] = _aw[3] ^ _bw[3] + _dw[4] = _aw[4] ^ _bw[4] + _dw[5] = _aw[5] ^ _bw[5] + _dw[6] = _aw[6] ^ _bw[6] + _dw[7] = _aw[7] ^ _bw[7] } } diff --git a/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/README.md b/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/README.md index 15e9871..9a760d2 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/README.md +++ b/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/README.md @@ -62,7 +62,7 @@ func client() { panic(err) } - // Stream implements net.Conn + // Stream implements io.ReadWriteCloser stream.Write([]byte("ping")) } @@ -94,4 +94,4 @@ func server() { ## Status -Beta +Stable diff --git a/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/session.go b/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/session.go index a06f2ec..5c759c0 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/session.go +++ b/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/session.go @@ -16,10 +16,19 @@ const ( const ( errBrokenPipe = "broken pipe" - errConnReset = "connection reset by peer" errInvalidProtocol = "invalid protocol version" ) +type writeRequest struct { + frame Frame + result chan writeResult +} + +type writeResult struct { + n int + err error +} + // Session defines a multiplexed connection for streams type Session struct { conn io.ReadWriteCloser @@ -38,7 +47,12 @@ type Session struct { dieLock sync.Mutex chAccepts chan *Stream + xmitPool sync.Pool dataReady int32 // flag data has arrived + + deadline atomic.Value + + writes chan writeRequest } func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session { @@ -50,12 +64,18 @@ func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session { s.chAccepts = make(chan *Stream, defaultAcceptBacklog) s.bucket = int32(config.MaxReceiveBuffer) s.bucketCond = sync.NewCond(&sync.Mutex{}) + s.xmitPool.New = func() interface{} { + return make([]byte, (1<<16)+headerSize) + } + s.writes = make(chan writeRequest) + if client { s.nextStreamID = 1 } else { s.nextStreamID = 2 } go s.recvLoop() + go s.sendLoop() go s.keepalive() return s } @@ -82,9 +102,17 @@ func (s *Session) OpenStream() (*Stream, error) { // AcceptStream is used to block until the next available stream // is ready to be accepted. func (s *Session) AcceptStream() (*Stream, error) { + var deadline <-chan time.Time + if d, ok := s.deadline.Load().(time.Time); ok && !d.IsZero() { + timer := time.NewTimer(d.Sub(time.Now())) + defer timer.Stop() + deadline = timer.C + } select { case stream := <-s.chAccepts: return stream, nil + case <-deadline: + return nil, errTimeout case <-s.die: return nil, errors.New(errBrokenPipe) } @@ -93,13 +121,14 @@ func (s *Session) AcceptStream() (*Stream, error) { // Close is used to close the session and all streams. func (s *Session) Close() (err error) { s.dieLock.Lock() - defer s.dieLock.Unlock() select { case <-s.die: + s.dieLock.Unlock() return errors.New(errBrokenPipe) default: close(s.die) + s.dieLock.Unlock() s.streamLock.Lock() for k := range s.streams { s.streams[k].sessionClose() @@ -130,6 +159,13 @@ func (s *Session) NumStreams() int { return len(s.streams) } +// SetDeadline sets a deadline used by Accept* calls. +// A zero time value disables the deadline. +func (s *Session) SetDeadline(t time.Time) error { + s.deadline.Store(t) + return nil +} + // notify the session that a stream has closed func (s *Session) streamClosed(sid uint32) { s.streamLock.Lock() @@ -144,9 +180,12 @@ func (s *Session) streamClosed(sid uint32) { // returnTokens is called by stream to return token after read func (s *Session) returnTokens(n int) { - if atomic.AddInt32(&s.bucket, int32(n)) > 0 { + oldvalue := atomic.LoadInt32(&s.bucket) + newvalue := atomic.AddInt32(&s.bucket, int32(n)) + if oldvalue <= 0 && newvalue > 0 { s.bucketCond.Signal() } + } // session read a frame from underlying connection @@ -250,26 +289,56 @@ func (s *Session) keepalive() { } } +func (s *Session) sendLoop() { + for { + select { + case <-s.die: + return + case request, ok := <-s.writes: + if !ok { + continue + } + buf := s.xmitPool.Get().([]byte) + buf[0] = request.frame.ver + buf[1] = request.frame.cmd + binary.LittleEndian.PutUint16(buf[2:], uint16(len(request.frame.data))) + binary.LittleEndian.PutUint32(buf[4:], request.frame.sid) + copy(buf[headerSize:], request.frame.data) + + s.writeLock.Lock() + n, err := s.conn.Write(buf[:headerSize+len(request.frame.data)]) + s.writeLock.Unlock() + s.xmitPool.Put(buf) + + n -= headerSize + if n < 0 { + n = 0 + } + + result := writeResult{ + n: n, + err: err, + } + + request.result <- result + close(request.result) + } + } +} + // writeFrame writes the frame to the underlying connection // and returns the number of bytes written if successful func (s *Session) writeFrame(f Frame) (n int, err error) { - buf := make([]byte, headerSize+len(f.data)) - buf[0] = f.ver - buf[1] = f.cmd - binary.LittleEndian.PutUint16(buf[2:], uint16(len(f.data))) - binary.LittleEndian.PutUint32(buf[4:], f.sid) - copy(buf[headerSize:], f.data) + req := writeRequest{ + frame: f, + result: make(chan writeResult, 1), + } + select { + case <-s.die: + return 0, errors.New(errBrokenPipe) + case s.writes <- req: + } - s.writeLock.Lock() - n, err = s.conn.Write(buf) - s.writeLock.Unlock() - return n, err -} - -// writeBinary writes the byte slice to the underlying connection -func (s *Session) writeBinary(bts []byte) (n int, err error) { - s.writeLock.Lock() - n, err = s.conn.Write(bts) - s.writeLock.Unlock() - return n, err + result := <-req.result + return result.n, result.err } diff --git a/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/stream.go b/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/stream.go index 8c44dd8..34e4abb 100644 --- a/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/stream.go +++ b/cmd/gost/vendor/gopkg.in/xtaci/smux.v1/stream.go @@ -2,24 +2,28 @@ package smux import ( "bytes" - "encoding/binary" + "io" + "net" "sync" "sync/atomic" + "time" "github.com/pkg/errors" ) // Stream implements io.ReadWriteCloser type Stream struct { - id uint32 - rstflag int32 - sess *Session - buffer bytes.Buffer - bufferLock sync.Mutex - frameSize int - chReadEvent chan struct{} // notify a read event - die chan struct{} // flag the stream has closed - dieLock sync.Mutex + id uint32 + rstflag int32 + sess *Session + buffer bytes.Buffer + bufferLock sync.Mutex + frameSize int + chReadEvent chan struct{} // notify a read event + die chan struct{} // flag the stream has closed + dieLock sync.Mutex + readDeadline atomic.Value + writeDeadline atomic.Value } // newStream initiates a Stream struct @@ -35,10 +39,19 @@ func newStream(id uint32, frameSize int, sess *Session) *Stream { // Read implements io.ReadWriteCloser func (s *Stream) Read(b []byte) (n int, err error) { + var deadline <-chan time.Time + if d, ok := s.readDeadline.Load().(time.Time); ok && !d.IsZero() { + timer := time.NewTimer(d.Sub(time.Now())) + defer timer.Stop() + deadline = timer.C + } + READ: select { case <-s.die: return 0, errors.New(errBrokenPipe) + case <-deadline: + return n, errTimeout default: } @@ -51,12 +64,14 @@ READ: return n, nil } else if atomic.LoadInt32(&s.rstflag) == 1 { _ = s.Close() - return 0, errors.New(errConnReset) + return 0, io.EOF } select { case <-s.chReadEvent: goto READ + case <-deadline: + return n, errTimeout case <-s.die: return 0, errors.New(errBrokenPipe) } @@ -64,6 +79,13 @@ READ: // Write implements io.ReadWriteCloser func (s *Stream) Write(b []byte) (n int, err error) { + var deadline <-chan time.Time + if d, ok := s.writeDeadline.Load().(time.Time); ok && !d.IsZero() { + timer := time.NewTimer(d.Sub(time.Now())) + defer timer.Stop() + deadline = timer.C + } + select { case <-s.die: return 0, errors.New(errBrokenPipe) @@ -71,42 +93,82 @@ func (s *Stream) Write(b []byte) (n int, err error) { } frames := s.split(b, cmdPSH, s.id) - // preallocate buffer - buffer := make([]byte, len(frames)*headerSize+len(b)) - bts := buffer - - // combine frames into a large blob + sent := 0 for k := range frames { - bts[0] = version - bts[1] = frames[k].cmd - binary.LittleEndian.PutUint16(bts[2:], uint16(len(frames[k].data))) - binary.LittleEndian.PutUint32(bts[4:], frames[k].sid) - copy(bts[headerSize:], frames[k].data) - bts = bts[len(frames[k].data)+headerSize:] - } + req := writeRequest{ + frame: frames[k], + result: make(chan writeResult, 1), + } - if _, err = s.sess.writeBinary(buffer); err != nil { - return 0, err + select { + case s.sess.writes <- req: + case <-s.die: + return sent, errors.New(errBrokenPipe) + case <-deadline: + return sent, errTimeout + } + + select { + case result := <-req.result: + sent += result.n + if result.err != nil { + return sent, result.err + } + case <-s.die: + return sent, errors.New(errBrokenPipe) + case <-deadline: + return sent, errTimeout + } } - return len(b), nil + return sent, nil } // Close implements io.ReadWriteCloser func (s *Stream) Close() error { s.dieLock.Lock() - defer s.dieLock.Unlock() select { case <-s.die: + s.dieLock.Unlock() return errors.New(errBrokenPipe) default: close(s.die) + s.dieLock.Unlock() s.sess.streamClosed(s.id) _, err := s.sess.writeFrame(newFrame(cmdRST, s.id)) return err } } +// SetReadDeadline sets the read deadline as defined by +// net.Conn.SetReadDeadline. +// A zero time value disables the deadline. +func (s *Stream) SetReadDeadline(t time.Time) error { + s.readDeadline.Store(t) + return nil +} + +// SetWriteDeadline sets the write deadline as defined by +// net.Conn.SetWriteDeadline. +// A zero time value disables the deadline. +func (s *Stream) SetWriteDeadline(t time.Time) error { + s.writeDeadline.Store(t) + return nil +} + +// SetDeadline sets both read and write deadlines as defined by +// net.Conn.SetDeadline. +// A zero time value disables the deadlines. +func (s *Stream) SetDeadline(t time.Time) error { + if err := s.SetReadDeadline(t); err != nil { + return err + } + if err := s.SetWriteDeadline(t); err != nil { + return err + } + return nil +} + // session closes the stream func (s *Stream) sessionClose() { s.dieLock.Lock() @@ -119,6 +181,26 @@ func (s *Stream) sessionClose() { } } +// LocalAddr satisfies net.Conn interface +func (s *Stream) LocalAddr() net.Addr { + if ts, ok := s.sess.conn.(interface { + LocalAddr() net.Addr + }); ok { + return ts.LocalAddr() + } + return nil +} + +// RemoteAddr satisfies net.Conn interface +func (s *Stream) RemoteAddr() net.Addr { + if ts, ok := s.sess.conn.(interface { + RemoteAddr() net.Addr + }); ok { + return ts.RemoteAddr() + } + return nil +} + // pushBytes a slice into buffer func (s *Stream) pushBytes(p []byte) { s.bufferLock.Lock() @@ -164,3 +246,11 @@ func (s *Stream) notifyReadEvent() { func (s *Stream) markRST() { atomic.StoreInt32(&s.rstflag, 1) } + +var errTimeout error = &timeoutError{} + +type timeoutError struct{} + +func (e *timeoutError) Error() string { return "i/o timeout" } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } diff --git a/cmd/gost/vendor/vendor.json b/cmd/gost/vendor/vendor.json index 51f6d88..57223ca 100644 --- a/cmd/gost/vendor/vendor.json +++ b/cmd/gost/vendor/vendor.json @@ -8,12 +8,6 @@ "revision": "c91e78db502ff629614837aacb7aa4efa61c651a", "revisionTime": "2016-04-30T09:49:23Z" }, - { - "checksumSHA1": "QPs3L3mjPoi+a9GJCjW8HhyJczM=", - "path": "github.com/codahale/chacha20", - "revision": "ec07b4f69a3f70b1dd2a8ad77230deb1ba5d6953", - "revisionTime": "2015-11-07T02:50:05Z" - }, { "checksumSHA1": "aIhLeVAIrsjs63CwqmU3+GU8yT4=", "path": "github.com/ginuerzh/gosocks4", @@ -68,12 +62,6 @@ "revision": "09cded8978dc9e80714c4d85b0322337b0a1e5e0", "revisionTime": "2016-03-02T07:53:16Z" }, - { - "checksumSHA1": "BM6ZlNJmtKy3GBoWwg2X55gnZ4A=", - "path": "github.com/klauspost/crc32", - "revision": "cb6bfca970f6908083f26f39a79009d608efd5cd", - "revisionTime": "2016-10-16T15:41:25Z" - }, { "checksumSHA1": "dwSGkUfh3A2h0VkXndzBX/27hVc=", "path": "github.com/klauspost/reedsolomon", @@ -291,16 +279,16 @@ "revisionTime": "2016-12-15T22:53:35Z" }, { - "checksumSHA1": "nkIlj9QTxHQ78Vb+VgjhXZ4rZ3E=", + "checksumSHA1": "SbBORpjEg3VfPfdSrW82pa3f9Io=", "path": "gopkg.in/xtaci/kcp-go.v2", - "revision": "6610d527ea5c4890cf593796ff8ff1f10486bb68", - "revisionTime": "2016-09-08T14:44:41Z" + "revision": "6da5044c742f24f05b00db9214b57b2ac943c9ab", + "revisionTime": "2017-01-20T08:43:10Z" }, { - "checksumSHA1": "aIqXwA82JxLOXcgmuVSgcRqdJvU=", + "checksumSHA1": "EutBuLS2elfcDCMifXNMGj9farQ=", "path": "gopkg.in/xtaci/smux.v1", - "revision": "9f2b528a60917e6446273926f4c676cac759d2b0", - "revisionTime": "2016-09-22T10:26:45Z" + "revision": "427dd804ce9fb0a9e7b27a628f68a124fb0d67a6", + "revisionTime": "2016-11-29T15:03:00Z" } ], "rootPath": "github.com/ginuerzh/gost/cmd/gost"