update kcp vendor
This commit is contained in:
parent
69399ee74f
commit
1e709ceaba
21
cmd/gost/vendor/github.com/codahale/chacha20/LICENSE
generated
vendored
21
cmd/gost/vendor/github.com/codahale/chacha20/LICENSE
generated
vendored
@ -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.
|
|
8
cmd/gost/vendor/github.com/codahale/chacha20/README.md
generated
vendored
8
cmd/gost/vendor/github.com/codahale/chacha20/README.md
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
chacha20
|
|
||||||
========
|
|
||||||
|
|
||||||
[](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).
|
|
235
cmd/gost/vendor/github.com/codahale/chacha20/chacha20.go
generated
vendored
235
cmd/gost/vendor/github.com/codahale/chacha20/chacha20.go
generated
vendored
@ -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
|
|
||||||
}
|
|
166
cmd/gost/vendor/github.com/codahale/chacha20/core_ref.go
generated
vendored
166
cmd/gost/vendor/github.com/codahale/chacha20/core_ref.go
generated
vendored
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
28
cmd/gost/vendor/github.com/klauspost/crc32/LICENSE
generated
vendored
28
cmd/gost/vendor/github.com/klauspost/crc32/LICENSE
generated
vendored
@ -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.
|
|
87
cmd/gost/vendor/github.com/klauspost/crc32/README.md
generated
vendored
87
cmd/gost/vendor/github.com/klauspost/crc32/README.md
generated
vendored
@ -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.
|
|
||||||
|
|
||||||
[](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.
|
|
207
cmd/gost/vendor/github.com/klauspost/crc32/crc32.go
generated
vendored
207
cmd/gost/vendor/github.com/klauspost/crc32/crc32.go
generated
vendored
@ -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)
|
|
||||||
}
|
|
230
cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.go
generated
vendored
230
cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.go
generated
vendored
@ -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)
|
|
||||||
}
|
|
319
cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.s
generated
vendored
319
cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64.s
generated
vendored
@ -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
|
|
43
cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.go
generated
vendored
43
cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.go
generated
vendored
@ -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") }
|
|
67
cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.s
generated
vendored
67
cmd/gost/vendor/github.com/klauspost/crc32/crc32_amd64p32.s
generated
vendored
@ -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
|
|
||||||
|
|
89
cmd/gost/vendor/github.com/klauspost/crc32/crc32_generic.go
generated
vendored
89
cmd/gost/vendor/github.com/klauspost/crc32/crc32_generic.go
generated
vendored
@ -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)
|
|
||||||
}
|
|
15
cmd/gost/vendor/github.com/klauspost/crc32/crc32_otherarch.go
generated
vendored
15
cmd/gost/vendor/github.com/klauspost/crc32/crc32_otherarch.go
generated
vendored
@ -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") }
|
|
91
cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.go
generated
vendored
91
cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.go
generated
vendored
@ -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)
|
|
||||||
}
|
|
249
cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.s
generated
vendored
249
cmd/gost/vendor/github.com/klauspost/crc32/crc32_s390x.s
generated
vendored
@ -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
|
|
25
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/README.md
generated
vendored
25
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/README.md
generated
vendored
@ -1,4 +1,5 @@
|
|||||||
# kcp-go
|
<img src="kcp-go.png" alt="kcp-go" height="50px" />
|
||||||
|
|
||||||
|
|
||||||
[![GoDoc][1]][2] [![Powered][9]][10] [![MIT licensed][11]][12] [![Build Status][3]][4] [![Go Report Card][5]][6] [![Coverage Statusd][7]][8]
|
[![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
|
## 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
|
## Features
|
||||||
|
|
||||||
1. Optimized for ***Real-Time Strategy Game***.
|
1. Optimized for ***Online Games, Audio/Video Streaming***.
|
||||||
1. Compatible with [skywind3000's](https://github.com/skywind3000) C version with modifications.
|
1. Compatible with [skywind3000's](https://github.com/skywind3000) C version with optimizations.
|
||||||
1. ***Cache friendly*** and ***Memory optimized*** design in golang.
|
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. Compatible with [net.Conn](https://golang.org/pkg/net/#Conn) and [net.Listener](https://golang.org/pkg/net/#Listener).
|
||||||
1. [FEC(Forward Error Correction)](https://en.wikipedia.org/wiki/Forward_error_correction) Support with [Reed-Solomon Codes](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction)
|
1. [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
|
## Specification
|
||||||
|
|
||||||
# <img src="frame.png" alt="Frame Format" height="160px" />
|
<img src="frame.png" alt="Frame Format" height="109px" />
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@ -75,14 +76,14 @@ PASS
|
|||||||
ok github.com/xtaci/kcp-go 0.600s
|
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
|
## 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
|
2. https://github.com/skywind3000/kcp -- A Fast and Reliable ARQ Protocol
|
||||||
3. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go
|
3. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go
|
||||||
|
|
||||||
## Donation
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
All donations on this project will be used to support the development of [gonet/2](http://gonet2.github.io/).
|
|
||||||
|
150
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/crypt.go
generated
vendored
150
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/crypt.go
generated
vendored
@ -20,7 +20,9 @@ var (
|
|||||||
saltxor = `sH3CIVoF#rWLtJo6`
|
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 {
|
type BlockCrypt interface {
|
||||||
// Encrypt encrypts the whole block in src into dst.
|
// Encrypt encrypts the whole block in src into dst.
|
||||||
// Dst and src may point at the same memory.
|
// Dst and src may point at the same memory.
|
||||||
@ -31,40 +33,35 @@ type BlockCrypt interface {
|
|||||||
Decrypt(dst, src []byte)
|
Decrypt(dst, src []byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Salsa20BlockCrypt implements BlockCrypt
|
type salsa20BlockCrypt struct {
|
||||||
type Salsa20BlockCrypt struct {
|
|
||||||
key [32]byte
|
key [32]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSalsa20BlockCrypt initates BlockCrypt by the given key
|
// NewSalsa20BlockCrypt https://en.wikipedia.org/wiki/Salsa20
|
||||||
func NewSalsa20BlockCrypt(key []byte) (BlockCrypt, error) {
|
func NewSalsa20BlockCrypt(key []byte) (BlockCrypt, error) {
|
||||||
c := new(Salsa20BlockCrypt)
|
c := new(salsa20BlockCrypt)
|
||||||
copy(c.key[:], key)
|
copy(c.key[:], key)
|
||||||
return c, nil
|
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)
|
salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key)
|
||||||
copy(dst[:8], src[:8])
|
copy(dst[:8], src[:8])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt implements Decrypt interface
|
type twofishBlockCrypt struct {
|
||||||
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 {
|
|
||||||
encbuf []byte
|
encbuf []byte
|
||||||
decbuf []byte
|
decbuf []byte
|
||||||
block cipher.Block
|
block cipher.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTwofishBlockCrypt initates BlockCrypt by the given key
|
// NewTwofishBlockCrypt https://en.wikipedia.org/wiki/Twofish
|
||||||
func NewTwofishBlockCrypt(key []byte) (BlockCrypt, error) {
|
func NewTwofishBlockCrypt(key []byte) (BlockCrypt, error) {
|
||||||
c := new(TwofishBlockCrypt)
|
c := new(twofishBlockCrypt)
|
||||||
block, err := twofish.NewCipher(key)
|
block, err := twofish.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -75,22 +72,18 @@ func NewTwofishBlockCrypt(key []byte) (BlockCrypt, error) {
|
|||||||
return c, nil
|
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
|
type tripleDESBlockCrypt struct {
|
||||||
func (c *TwofishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
|
|
||||||
|
|
||||||
// TripleDESBlockCrypt implements BlockCrypt
|
|
||||||
type TripleDESBlockCrypt struct {
|
|
||||||
encbuf []byte
|
encbuf []byte
|
||||||
decbuf []byte
|
decbuf []byte
|
||||||
block cipher.Block
|
block cipher.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTripleDESBlockCrypt initates BlockCrypt by the given key
|
// NewTripleDESBlockCrypt https://en.wikipedia.org/wiki/Triple_DES
|
||||||
func NewTripleDESBlockCrypt(key []byte) (BlockCrypt, error) {
|
func NewTripleDESBlockCrypt(key []byte) (BlockCrypt, error) {
|
||||||
c := new(TripleDESBlockCrypt)
|
c := new(tripleDESBlockCrypt)
|
||||||
block, err := des.NewTripleDESCipher(key)
|
block, err := des.NewTripleDESCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -101,22 +94,18 @@ func NewTripleDESBlockCrypt(key []byte) (BlockCrypt, error) {
|
|||||||
return c, nil
|
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
|
type cast5BlockCrypt struct {
|
||||||
func (c *TripleDESBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
|
|
||||||
|
|
||||||
// Cast5BlockCrypt implements BlockCrypt
|
|
||||||
type Cast5BlockCrypt struct {
|
|
||||||
encbuf []byte
|
encbuf []byte
|
||||||
decbuf []byte
|
decbuf []byte
|
||||||
block cipher.Block
|
block cipher.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCast5BlockCrypt initates BlockCrypt by the given key
|
// NewCast5BlockCrypt https://en.wikipedia.org/wiki/CAST-128
|
||||||
func NewCast5BlockCrypt(key []byte) (BlockCrypt, error) {
|
func NewCast5BlockCrypt(key []byte) (BlockCrypt, error) {
|
||||||
c := new(Cast5BlockCrypt)
|
c := new(cast5BlockCrypt)
|
||||||
block, err := cast5.NewCipher(key)
|
block, err := cast5.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -127,22 +116,18 @@ func NewCast5BlockCrypt(key []byte) (BlockCrypt, error) {
|
|||||||
return c, nil
|
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
|
type blowfishBlockCrypt struct {
|
||||||
func (c *Cast5BlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
|
|
||||||
|
|
||||||
// BlowfishBlockCrypt implements BlockCrypt
|
|
||||||
type BlowfishBlockCrypt struct {
|
|
||||||
encbuf []byte
|
encbuf []byte
|
||||||
decbuf []byte
|
decbuf []byte
|
||||||
block cipher.Block
|
block cipher.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlowfishBlockCrypt initates BlockCrypt by the given key
|
// NewBlowfishBlockCrypt https://en.wikipedia.org/wiki/Blowfish_(cipher)
|
||||||
func NewBlowfishBlockCrypt(key []byte) (BlockCrypt, error) {
|
func NewBlowfishBlockCrypt(key []byte) (BlockCrypt, error) {
|
||||||
c := new(BlowfishBlockCrypt)
|
c := new(blowfishBlockCrypt)
|
||||||
block, err := blowfish.NewCipher(key)
|
block, err := blowfish.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -153,22 +138,18 @@ func NewBlowfishBlockCrypt(key []byte) (BlockCrypt, error) {
|
|||||||
return c, nil
|
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
|
type aesBlockCrypt struct {
|
||||||
func (c *BlowfishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
|
|
||||||
|
|
||||||
// AESBlockCrypt implements BlockCrypt
|
|
||||||
type AESBlockCrypt struct {
|
|
||||||
encbuf []byte
|
encbuf []byte
|
||||||
decbuf []byte
|
decbuf []byte
|
||||||
block cipher.Block
|
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) {
|
func NewAESBlockCrypt(key []byte) (BlockCrypt, error) {
|
||||||
c := new(AESBlockCrypt)
|
c := new(aesBlockCrypt)
|
||||||
block, err := aes.NewCipher(key)
|
block, err := aes.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -179,22 +160,18 @@ func NewAESBlockCrypt(key []byte) (BlockCrypt, error) {
|
|||||||
return c, nil
|
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
|
type teaBlockCrypt struct {
|
||||||
func (c *AESBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
|
|
||||||
|
|
||||||
// TEABlockCrypt implements BlockCrypt
|
|
||||||
type TEABlockCrypt struct {
|
|
||||||
encbuf []byte
|
encbuf []byte
|
||||||
decbuf []byte
|
decbuf []byte
|
||||||
block cipher.Block
|
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) {
|
func NewTEABlockCrypt(key []byte) (BlockCrypt, error) {
|
||||||
c := new(TEABlockCrypt)
|
c := new(teaBlockCrypt)
|
||||||
block, err := tea.NewCipherWithRounds(key, 16)
|
block, err := tea.NewCipherWithRounds(key, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -205,22 +182,18 @@ func NewTEABlockCrypt(key []byte) (BlockCrypt, error) {
|
|||||||
return c, nil
|
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
|
type xteaBlockCrypt struct {
|
||||||
func (c *TEABlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
|
|
||||||
|
|
||||||
// XTEABlockCrypt implements BlockCrypt
|
|
||||||
type XTEABlockCrypt struct {
|
|
||||||
encbuf []byte
|
encbuf []byte
|
||||||
decbuf []byte
|
decbuf []byte
|
||||||
block cipher.Block
|
block cipher.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewXTEABlockCrypt initate BlockCrypt by the given key
|
// NewXTEABlockCrypt https://en.wikipedia.org/wiki/XTEA
|
||||||
func NewXTEABlockCrypt(key []byte) (BlockCrypt, error) {
|
func NewXTEABlockCrypt(key []byte) (BlockCrypt, error) {
|
||||||
c := new(XTEABlockCrypt)
|
c := new(xteaBlockCrypt)
|
||||||
block, err := xtea.NewCipher(key)
|
block, err := xtea.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -231,43 +204,32 @@ func NewXTEABlockCrypt(key []byte) (BlockCrypt, error) {
|
|||||||
return c, nil
|
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
|
type simpleXORBlockCrypt struct {
|
||||||
func (c *XTEABlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
|
|
||||||
|
|
||||||
// SimpleXORBlockCrypt implements BlockCrypt
|
|
||||||
type SimpleXORBlockCrypt struct {
|
|
||||||
xortbl []byte
|
xortbl []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSimpleXORBlockCrypt initate BlockCrypt by the given key
|
// NewSimpleXORBlockCrypt simple xor with key expanding
|
||||||
func NewSimpleXORBlockCrypt(key []byte) (BlockCrypt, error) {
|
func NewSimpleXORBlockCrypt(key []byte) (BlockCrypt, error) {
|
||||||
c := new(SimpleXORBlockCrypt)
|
c := new(simpleXORBlockCrypt)
|
||||||
c.xortbl = pbkdf2.Key(key, []byte(saltxor), 32, mtuLimit, sha1.New)
|
c.xortbl = pbkdf2.Key(key, []byte(saltxor), 32, mtuLimit, sha1.New)
|
||||||
return c, nil
|
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
|
type noneBlockCrypt struct{}
|
||||||
func (c *SimpleXORBlockCrypt) Decrypt(dst, src []byte) { xorBytes(dst, src, c.xortbl) }
|
|
||||||
|
|
||||||
// NoneBlockCrypt simple returns the plaintext
|
// NewNoneBlockCrypt does nothing but copying
|
||||||
type NoneBlockCrypt struct{}
|
|
||||||
|
|
||||||
// NewNoneBlockCrypt initate by the given key
|
|
||||||
func NewNoneBlockCrypt(key []byte) (BlockCrypt, error) {
|
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) }
|
||||||
func (c *NoneBlockCrypt) Encrypt(dst, src []byte) { copy(dst, src) }
|
func (c *noneBlockCrypt) Decrypt(dst, src []byte) { copy(dst, src) }
|
||||||
|
|
||||||
// Decrypt implements Decrypt interface
|
|
||||||
func (c *NoneBlockCrypt) Decrypt(dst, src []byte) { copy(dst, src) }
|
|
||||||
|
|
||||||
// packet encryption with local CFB mode
|
// packet encryption with local CFB mode
|
||||||
func encrypt(block cipher.Block, dst, src, buf []byte) {
|
func encrypt(block cipher.Block, dst, src, buf []byte) {
|
||||||
|
31
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/fec.go
generated
vendored
31
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/fec.go
generated
vendored
@ -2,7 +2,7 @@ package kcp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"sync"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/klauspost/reedsolomon"
|
"github.com/klauspost/reedsolomon"
|
||||||
)
|
)
|
||||||
@ -26,10 +26,10 @@ type (
|
|||||||
next uint32 // next seqid
|
next uint32 // next seqid
|
||||||
enc reedsolomon.Encoder
|
enc reedsolomon.Encoder
|
||||||
shards [][]byte
|
shards [][]byte
|
||||||
|
shards2 [][]byte // for calcECC
|
||||||
shardsflag []bool
|
shardsflag []bool
|
||||||
paws uint32 // Protect Against Wrapped Sequence numbers
|
paws uint32 // Protect Against Wrapped Sequence numbers
|
||||||
lastCheck uint32
|
lastCheck uint32
|
||||||
xmitBuf sync.Pool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fecPacket struct {
|
fecPacket struct {
|
||||||
@ -60,11 +60,8 @@ func newFEC(rxlimit, dataShards, parityShards int) *FEC {
|
|||||||
}
|
}
|
||||||
fec.enc = enc
|
fec.enc = enc
|
||||||
fec.shards = make([][]byte, fec.shardSize)
|
fec.shards = make([][]byte, fec.shardSize)
|
||||||
|
fec.shards2 = make([][]byte, fec.shardSize)
|
||||||
fec.shardsflag = make([]bool, fec.shardSize)
|
fec.shardsflag = make([]bool, fec.shardSize)
|
||||||
fec.xmitBuf.New = func() interface{} {
|
|
||||||
return make([]byte, mtuLimit)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fec
|
return fec
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,9 +72,8 @@ func (fec *FEC) decode(data []byte) fecPacket {
|
|||||||
pkt.flag = binary.LittleEndian.Uint16(data[4:])
|
pkt.flag = binary.LittleEndian.Uint16(data[4:])
|
||||||
pkt.ts = currentMs()
|
pkt.ts = currentMs()
|
||||||
// allocate memory & copy
|
// allocate memory & copy
|
||||||
buf := fec.xmitBuf.Get().([]byte)
|
buf := xmitBuf.Get().([]byte)[:len(data)-6]
|
||||||
n := copy(buf, data[6:])
|
copy(buf, data[6:])
|
||||||
xorBytes(buf[n:], buf[n:], buf[n:])
|
|
||||||
pkt.data = buf
|
pkt.data = buf
|
||||||
return pkt
|
return pkt
|
||||||
}
|
}
|
||||||
@ -107,7 +103,7 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) {
|
|||||||
if now-fec.rx[k].ts < fecExpire {
|
if now-fec.rx[k].ts < fecExpire {
|
||||||
rx = append(rx, fec.rx[k])
|
rx = append(rx, fec.rx[k])
|
||||||
} else {
|
} else {
|
||||||
fec.xmitBuf.Put(fec.rx[k].data)
|
xmitBuf.Put(fec.rx[k].data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fec.rx = rx
|
fec.rx = rx
|
||||||
@ -119,7 +115,7 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) {
|
|||||||
insertIdx := 0
|
insertIdx := 0
|
||||||
for i := n; i >= 0; i-- {
|
for i := n; i >= 0; i-- {
|
||||||
if pkt.seqid == fec.rx[i].seqid { // de-duplicate
|
if pkt.seqid == fec.rx[i].seqid { // de-duplicate
|
||||||
fec.xmitBuf.Put(pkt.data)
|
xmitBuf.Put(pkt.data)
|
||||||
return nil
|
return nil
|
||||||
} else if pkt.seqid > fec.rx[i].seqid { // insertion
|
} else if pkt.seqid > fec.rx[i].seqid { // insertion
|
||||||
insertIdx = i + 1
|
insertIdx = i + 1
|
||||||
@ -184,7 +180,7 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) {
|
|||||||
|
|
||||||
if numDataShard == fec.dataShards { // no lost
|
if numDataShard == fec.dataShards { // no lost
|
||||||
for i := first; i < first+numshard; i++ { // free
|
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:])
|
copy(fec.rx[first:], fec.rx[first+numshard:])
|
||||||
for i := 0; i < numshard; i++ { // dereference
|
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
|
} else if numshard >= fec.dataShards { // recoverable
|
||||||
for k := range shards {
|
for k := range shards {
|
||||||
if shards[k] != nil {
|
if shards[k] != nil {
|
||||||
|
dlen := len(shards[k])
|
||||||
shards[k] = shards[k][:maxlen]
|
shards[k] = shards[k][:maxlen]
|
||||||
|
xorBytes(shards[k][dlen:], shards[k][dlen:], shards[k][dlen:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := fec.enc.Reconstruct(shards); err == nil {
|
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
|
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:])
|
copy(fec.rx[first:], fec.rx[first+numshard:])
|
||||||
for i := 0; i < numshard; i++ { // dereference
|
for i := 0; i < numshard; i++ { // dereference
|
||||||
@ -218,7 +216,10 @@ func (fec *FEC) input(pkt fecPacket) (recovered [][]byte) {
|
|||||||
|
|
||||||
// keep rxlimit
|
// keep rxlimit
|
||||||
if len(fec.rx) > fec.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[0].data = nil
|
||||||
fec.rx = fec.rx[1:]
|
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 {
|
if len(data) != fec.shardSize {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
shards := make([][]byte, fec.shardSize)
|
shards := fec.shards2
|
||||||
for k := range shards {
|
for k := range shards {
|
||||||
shards[k] = data[k][offset:maxlen]
|
shards[k] = data[k][offset:maxlen]
|
||||||
}
|
}
|
||||||
|
BIN
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/frame.png
generated
vendored
BIN
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/frame.png
generated
vendored
Binary file not shown.
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 35 KiB |
BIN
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp-go.png
generated
vendored
Normal file
BIN
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp-go.png
generated
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
149
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp.go
generated
vendored
149
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/kcp.go
generated
vendored
@ -2,7 +2,6 @@
|
|||||||
package kcp
|
package kcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/heap"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
@ -123,13 +122,6 @@ func (seg *Segment) encode(ptr []byte) []byte {
|
|||||||
return ptr
|
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
|
// KCP defines a single KCP connection
|
||||||
type KCP struct {
|
type KCP struct {
|
||||||
conv, mtu, mss, state uint32
|
conv, mtu, mss, state uint32
|
||||||
@ -137,7 +129,7 @@ type KCP struct {
|
|||||||
ssthresh uint32
|
ssthresh uint32
|
||||||
rx_rttval, rx_srtt, rx_rto, rx_minrto uint32
|
rx_rttval, rx_srtt, rx_rto, rx_minrto uint32
|
||||||
snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe uint32
|
snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe uint32
|
||||||
current, interval, ts_flush, xmit uint32
|
interval, ts_flush, xmit uint32
|
||||||
nodelay, updated uint32
|
nodelay, updated uint32
|
||||||
ts_probe, probe_wait uint32
|
ts_probe, probe_wait uint32
|
||||||
dead_link, incr uint32
|
dead_link, incr uint32
|
||||||
@ -150,33 +142,17 @@ type KCP struct {
|
|||||||
snd_buf []Segment
|
snd_buf []Segment
|
||||||
rcv_buf []Segment
|
rcv_buf []Segment
|
||||||
|
|
||||||
acklist ACKList
|
acklist []ackItem
|
||||||
|
|
||||||
buffer []byte
|
buffer []byte
|
||||||
output Output
|
output Output
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACK packet to return
|
type ackItem struct {
|
||||||
type ACK struct {
|
|
||||||
sn uint32
|
sn uint32
|
||||||
ts 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
|
// NewKCP create a new kcp control object, 'conv' must equal in two endpoint
|
||||||
// from the same connection.
|
// from the same connection.
|
||||||
func NewKCP(conv uint32, output Output) *KCP {
|
func NewKCP(conv uint32, output Output) *KCP {
|
||||||
@ -198,6 +174,18 @@ func NewKCP(conv uint32, output Output) *KCP {
|
|||||||
return 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
|
// PeekSize checks the size of next message in the recv queue
|
||||||
func (kcp *KCP) PeekSize() (length int) {
|
func (kcp *KCP) PeekSize() (length int) {
|
||||||
if len(kcp.rcv_queue) == 0 {
|
if len(kcp.rcv_queue) == 0 {
|
||||||
@ -251,7 +239,7 @@ func (kcp *KCP) Recv(buffer []byte) (n int) {
|
|||||||
buffer = buffer[len(seg.data):]
|
buffer = buffer[len(seg.data):]
|
||||||
n += len(seg.data)
|
n += len(seg.data)
|
||||||
count++
|
count++
|
||||||
seg.data = nil
|
kcp.delSegment(seg)
|
||||||
if seg.frg == 0 {
|
if seg.frg == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -263,14 +251,13 @@ func (kcp *KCP) Recv(buffer []byte) (n int) {
|
|||||||
for k := range kcp.rcv_buf {
|
for k := range kcp.rcv_buf {
|
||||||
seg := &kcp.rcv_buf[k]
|
seg := &kcp.rcv_buf[k]
|
||||||
if seg.sn == kcp.rcv_nxt && len(kcp.rcv_queue) < int(kcp.rcv_wnd) {
|
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++
|
kcp.rcv_nxt++
|
||||||
count++
|
count++
|
||||||
seg.data = nil
|
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...)
|
||||||
kcp.rcv_buf = kcp.rcv_buf[count:]
|
kcp.rcv_buf = kcp.rcv_buf[count:]
|
||||||
|
|
||||||
// fast recover
|
// fast recover
|
||||||
@ -300,11 +287,12 @@ func (kcp *KCP) Send(buffer []byte) int {
|
|||||||
if len(buffer) < capacity {
|
if len(buffer) < capacity {
|
||||||
extend = len(buffer)
|
extend = len(buffer)
|
||||||
}
|
}
|
||||||
seg := NewSegment(len(old.data) + extend)
|
seg := kcp.newSegment(len(old.data) + extend)
|
||||||
seg.frg = 0
|
seg.frg = 0
|
||||||
copy(seg.data, old.data)
|
copy(seg.data, old.data)
|
||||||
copy(seg.data[len(old.data):], buffer)
|
copy(seg.data[len(old.data):], buffer)
|
||||||
buffer = buffer[extend:]
|
buffer = buffer[extend:]
|
||||||
|
kcp.delSegment(old)
|
||||||
kcp.snd_queue[n-1] = *seg
|
kcp.snd_queue[n-1] = *seg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,7 +323,7 @@ func (kcp *KCP) Send(buffer []byte) int {
|
|||||||
} else {
|
} else {
|
||||||
size = len(buffer)
|
size = len(buffer)
|
||||||
}
|
}
|
||||||
seg := NewSegment(size)
|
seg := kcp.newSegment(size)
|
||||||
copy(seg.data, buffer[:size])
|
copy(seg.data, buffer[:size])
|
||||||
if kcp.stream == 0 { // message mode
|
if kcp.stream == 0 { // message mode
|
||||||
seg.frg = uint32(count - i - 1)
|
seg.frg = uint32(count - i - 1)
|
||||||
@ -348,8 +336,8 @@ func (kcp *KCP) Send(buffer []byte) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://tools.ietf.org/html/rfc6298
|
|
||||||
func (kcp *KCP) update_ack(rtt int32) {
|
func (kcp *KCP) update_ack(rtt int32) {
|
||||||
|
// https://tools.ietf.org/html/rfc6298
|
||||||
var rto uint32
|
var rto uint32
|
||||||
if kcp.rx_srtt == 0 {
|
if kcp.rx_srtt == 0 {
|
||||||
kcp.rx_srtt = uint32(rtt)
|
kcp.rx_srtt = uint32(rtt)
|
||||||
@ -365,7 +353,7 @@ func (kcp *KCP) update_ack(rtt int32) {
|
|||||||
kcp.rx_srtt = 1
|
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)
|
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 {
|
for k := range kcp.snd_buf {
|
||||||
seg := &kcp.snd_buf[k]
|
seg := &kcp.snd_buf[k]
|
||||||
if sn == seg.sn {
|
if sn == seg.sn {
|
||||||
|
kcp.delSegment(seg)
|
||||||
copy(kcp.snd_buf[k:], kcp.snd_buf[k+1:])
|
copy(kcp.snd_buf[k:], kcp.snd_buf[k+1:])
|
||||||
kcp.snd_buf[len(kcp.snd_buf)-1] = Segment{}
|
kcp.snd_buf[len(kcp.snd_buf)-1] = Segment{}
|
||||||
kcp.snd_buf = kcp.snd_buf[:len(kcp.snd_buf)-1]
|
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 {
|
for k := range kcp.snd_buf {
|
||||||
seg := &kcp.snd_buf[k]
|
seg := &kcp.snd_buf[k]
|
||||||
if _itimediff(una, seg.sn) > 0 {
|
if _itimediff(una, seg.sn) > 0 {
|
||||||
|
kcp.delSegment(seg)
|
||||||
count++
|
count++
|
||||||
seg.data = nil
|
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -428,14 +417,14 @@ func (kcp *KCP) parse_una(una uint32) {
|
|||||||
|
|
||||||
// ack append
|
// ack append
|
||||||
func (kcp *KCP) ack_push(sn, ts uint32) {
|
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) {
|
func (kcp *KCP) parse_data(newseg *Segment) {
|
||||||
sn := newseg.sn
|
sn := newseg.sn
|
||||||
if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) >= 0 ||
|
if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) >= 0 ||
|
||||||
_itimediff(sn, kcp.rcv_nxt) < 0 {
|
_itimediff(sn, kcp.rcv_nxt) < 0 {
|
||||||
atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1)
|
kcp.delSegment(newseg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,6 +452,8 @@ func (kcp *KCP) parse_data(newseg *Segment) {
|
|||||||
copy(kcp.rcv_buf[insert_idx+1:], kcp.rcv_buf[insert_idx:])
|
copy(kcp.rcv_buf[insert_idx+1:], kcp.rcv_buf[insert_idx:])
|
||||||
kcp.rcv_buf[insert_idx] = *newseg
|
kcp.rcv_buf[insert_idx] = *newseg
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
kcp.delSegment(newseg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// move available data from rcv_buf -> rcv_queue
|
// 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 {
|
for k := range kcp.rcv_buf {
|
||||||
seg := &kcp.rcv_buf[k]
|
seg := &kcp.rcv_buf[k]
|
||||||
if seg.sn == kcp.rcv_nxt && len(kcp.rcv_queue) < int(kcp.rcv_wnd) {
|
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++
|
kcp.rcv_nxt++
|
||||||
count++
|
count++
|
||||||
seg.data = nil
|
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...)
|
||||||
kcp.rcv_buf = 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 maxack uint32
|
||||||
|
var recentack uint32
|
||||||
var flag int
|
var flag int
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var ts, sn, length, una, conv uint32
|
var ts, sn, length, una, conv uint32
|
||||||
var wnd uint16
|
var wnd uint16
|
||||||
@ -525,9 +517,6 @@ func (kcp *KCP) Input(data []byte, update_ack bool) int {
|
|||||||
kcp.shrink_buf()
|
kcp.shrink_buf()
|
||||||
|
|
||||||
if cmd == IKCP_CMD_ACK {
|
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.parse_ack(sn)
|
||||||
kcp.shrink_buf()
|
kcp.shrink_buf()
|
||||||
if flag == 0 {
|
if flag == 0 {
|
||||||
@ -536,11 +525,12 @@ func (kcp *KCP) Input(data []byte, update_ack bool) int {
|
|||||||
} else if _itimediff(sn, maxack) > 0 {
|
} else if _itimediff(sn, maxack) > 0 {
|
||||||
maxack = sn
|
maxack = sn
|
||||||
}
|
}
|
||||||
|
recentack = ts
|
||||||
} else if cmd == IKCP_CMD_PUSH {
|
} else if cmd == IKCP_CMD_PUSH {
|
||||||
if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) < 0 {
|
if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) < 0 {
|
||||||
kcp.ack_push(sn, ts)
|
kcp.ack_push(sn, ts)
|
||||||
if _itimediff(sn, kcp.rcv_nxt) >= 0 {
|
if _itimediff(sn, kcp.rcv_nxt) >= 0 {
|
||||||
seg := NewSegment(int(length))
|
seg := kcp.newSegment(int(length))
|
||||||
seg.conv = conv
|
seg.conv = conv
|
||||||
seg.cmd = uint32(cmd)
|
seg.cmd = uint32(cmd)
|
||||||
seg.frg = uint32(frg)
|
seg.frg = uint32(frg)
|
||||||
@ -550,7 +540,11 @@ func (kcp *KCP) Input(data []byte, update_ack bool) int {
|
|||||||
seg.una = una
|
seg.una = una
|
||||||
copy(seg.data, data[:length])
|
copy(seg.data, data[:length])
|
||||||
kcp.parse_data(seg)
|
kcp.parse_data(seg)
|
||||||
|
} else {
|
||||||
|
atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1)
|
||||||
}
|
}
|
||||||
} else if cmd == IKCP_CMD_WASK {
|
} else if cmd == IKCP_CMD_WASK {
|
||||||
// ready to send back IKCP_CMD_WINS in Ikcp_flush
|
// 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:]
|
data = data[length:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current := currentMs()
|
||||||
if flag != 0 && update_ack {
|
if flag != 0 && update_ack {
|
||||||
kcp.parse_fastack(maxack)
|
kcp.parse_fastack(maxack)
|
||||||
|
if _itimediff(current, recentack) >= 0 {
|
||||||
|
kcp.update_ack(_itimediff(current, recentack))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _itimediff(kcp.snd_una, una) > 0 {
|
if _itimediff(kcp.snd_una, una) > 0 {
|
||||||
@ -603,14 +601,10 @@ func (kcp *KCP) wnd_unused() int32 {
|
|||||||
|
|
||||||
// flush pending data
|
// flush pending data
|
||||||
func (kcp *KCP) flush() {
|
func (kcp *KCP) flush() {
|
||||||
current := kcp.current
|
|
||||||
buffer := kcp.buffer
|
buffer := kcp.buffer
|
||||||
change := 0
|
change := 0
|
||||||
lost := false
|
lost := false
|
||||||
|
|
||||||
if kcp.updated == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var seg Segment
|
var seg Segment
|
||||||
seg.conv = kcp.conv
|
seg.conv = kcp.conv
|
||||||
seg.cmd = IKCP_CMD_ACK
|
seg.cmd = IKCP_CMD_ACK
|
||||||
@ -619,25 +613,28 @@ func (kcp *KCP) flush() {
|
|||||||
|
|
||||||
// flush acknowledges
|
// flush acknowledges
|
||||||
ptr := buffer
|
ptr := buffer
|
||||||
for kcp.acklist.Len() > 0 {
|
for i, ack := range kcp.acklist {
|
||||||
size := len(buffer) - len(ptr)
|
size := len(buffer) - len(ptr)
|
||||||
if size+IKCP_OVERHEAD > int(kcp.mtu) {
|
if size+IKCP_OVERHEAD > int(kcp.mtu) {
|
||||||
kcp.output(buffer, size)
|
kcp.output(buffer, size)
|
||||||
ptr = buffer
|
ptr = buffer
|
||||||
}
|
}
|
||||||
ack := heap.Pop(&kcp.acklist).(ACK)
|
// filter jitters caused by bufferbloat
|
||||||
|
if ack.sn >= kcp.rcv_nxt || len(kcp.acklist)-1 == i {
|
||||||
seg.sn, seg.ts = ack.sn, ack.ts
|
seg.sn, seg.ts = ack.sn, ack.ts
|
||||||
ptr = seg.encode(ptr)
|
ptr = seg.encode(ptr)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
kcp.acklist = nil
|
kcp.acklist = nil
|
||||||
|
|
||||||
|
current := currentMs()
|
||||||
// probe window size (if remote window size equals zero)
|
// probe window size (if remote window size equals zero)
|
||||||
if kcp.rmt_wnd == 0 {
|
if kcp.rmt_wnd == 0 {
|
||||||
if kcp.probe_wait == 0 {
|
if kcp.probe_wait == 0 {
|
||||||
kcp.probe_wait = IKCP_PROBE_INIT
|
kcp.probe_wait = IKCP_PROBE_INIT
|
||||||
kcp.ts_probe = kcp.current + kcp.probe_wait
|
kcp.ts_probe = current + kcp.probe_wait
|
||||||
} else {
|
} else {
|
||||||
if _itimediff(kcp.current, kcp.ts_probe) >= 0 {
|
if _itimediff(current, kcp.ts_probe) >= 0 {
|
||||||
if kcp.probe_wait < IKCP_PROBE_INIT {
|
if kcp.probe_wait < IKCP_PROBE_INIT {
|
||||||
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 {
|
if kcp.probe_wait > IKCP_PROBE_LIMIT {
|
||||||
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
|
kcp.probe |= IKCP_ASK_SEND
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -684,6 +681,7 @@ func (kcp *KCP) flush() {
|
|||||||
cwnd = _imin_(kcp.cwnd, cwnd)
|
cwnd = _imin_(kcp.cwnd, cwnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sliding window, controlled by snd_nxt && sna_una+cwnd
|
||||||
count := 0
|
count := 0
|
||||||
for k := range kcp.snd_queue {
|
for k := range kcp.snd_queue {
|
||||||
if _itimediff(kcp.snd_nxt, kcp.snd_una+cwnd) >= 0 {
|
if _itimediff(kcp.snd_nxt, kcp.snd_una+cwnd) >= 0 {
|
||||||
@ -696,10 +694,8 @@ func (kcp *KCP) flush() {
|
|||||||
newseg.ts = current
|
newseg.ts = current
|
||||||
newseg.sn = kcp.snd_nxt
|
newseg.sn = kcp.snd_nxt
|
||||||
newseg.una = kcp.rcv_nxt
|
newseg.una = kcp.rcv_nxt
|
||||||
newseg.resendts = current
|
newseg.resendts = newseg.ts
|
||||||
newseg.rto = kcp.rx_rto
|
newseg.rto = kcp.rx_rto
|
||||||
newseg.fastack = 0
|
|
||||||
newseg.xmit = 0
|
|
||||||
kcp.snd_buf = append(kcp.snd_buf, newseg)
|
kcp.snd_buf = append(kcp.snd_buf, newseg)
|
||||||
kcp.snd_nxt++
|
kcp.snd_nxt++
|
||||||
count++
|
count++
|
||||||
@ -707,27 +703,29 @@ func (kcp *KCP) flush() {
|
|||||||
}
|
}
|
||||||
kcp.snd_queue = kcp.snd_queue[count:]
|
kcp.snd_queue = kcp.snd_queue[count:]
|
||||||
|
|
||||||
|
// flag pending data
|
||||||
|
hasPending := false
|
||||||
|
if count > 0 {
|
||||||
|
hasPending = true
|
||||||
|
}
|
||||||
|
|
||||||
// calculate resent
|
// calculate resent
|
||||||
resent := uint32(kcp.fastresend)
|
resent := uint32(kcp.fastresend)
|
||||||
if kcp.fastresend <= 0 {
|
if kcp.fastresend <= 0 {
|
||||||
resent = 0xffffffff
|
resent = 0xffffffff
|
||||||
}
|
}
|
||||||
rtomin := (kcp.rx_rto >> 3)
|
|
||||||
if kcp.nodelay != 0 {
|
|
||||||
rtomin = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// flush data segments
|
// flush data segments
|
||||||
nque := len(kcp.snd_queue)
|
|
||||||
var lostSegs, fastRetransSegs, earlyRetransSegs uint64
|
var lostSegs, fastRetransSegs, earlyRetransSegs uint64
|
||||||
for k := range kcp.snd_buf {
|
for k := range kcp.snd_buf {
|
||||||
|
current := currentMs()
|
||||||
segment := &kcp.snd_buf[k]
|
segment := &kcp.snd_buf[k]
|
||||||
needsend := false
|
needsend := false
|
||||||
if segment.xmit == 0 {
|
if segment.xmit == 0 {
|
||||||
needsend = true
|
needsend = true
|
||||||
segment.xmit++
|
segment.xmit++
|
||||||
segment.rto = kcp.rx_rto
|
segment.rto = kcp.rx_rto
|
||||||
segment.resendts = current + segment.rto + rtomin
|
segment.resendts = current + segment.rto
|
||||||
} else if _itimediff(current, segment.resendts) >= 0 {
|
} else if _itimediff(current, segment.resendts) >= 0 {
|
||||||
needsend = true
|
needsend = true
|
||||||
segment.xmit++
|
segment.xmit++
|
||||||
@ -740,15 +738,19 @@ func (kcp *KCP) flush() {
|
|||||||
segment.resendts = current + segment.rto
|
segment.resendts = current + segment.rto
|
||||||
lost = true
|
lost = true
|
||||||
lostSegs++
|
lostSegs++
|
||||||
} else if segment.fastack >= resent {
|
} else if segment.fastack >= resent { // fast retransmit
|
||||||
|
lastsend := segment.resendts - segment.rto
|
||||||
|
if _itimediff(current, lastsend) >= int32(kcp.rx_rto/4) {
|
||||||
needsend = true
|
needsend = true
|
||||||
segment.xmit++
|
segment.xmit++
|
||||||
segment.fastack = 0
|
segment.fastack = 0
|
||||||
segment.resendts = current + segment.rto
|
segment.resendts = current + segment.rto
|
||||||
change++
|
change++
|
||||||
fastRetransSegs++
|
fastRetransSegs++
|
||||||
} else if segment.fastack > 0 && nque == 0 {
|
}
|
||||||
// early retransmit
|
} else if segment.fastack > 0 && !hasPending { // early retransmit
|
||||||
|
lastsend := segment.resendts - segment.rto
|
||||||
|
if _itimediff(current, lastsend) >= int32(kcp.rx_rto/4) {
|
||||||
needsend = true
|
needsend = true
|
||||||
segment.xmit++
|
segment.xmit++
|
||||||
segment.fastack = 0
|
segment.fastack = 0
|
||||||
@ -756,6 +758,7 @@ func (kcp *KCP) flush() {
|
|||||||
change++
|
change++
|
||||||
earlyRetransSegs++
|
earlyRetransSegs++
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if needsend {
|
if needsend {
|
||||||
segment.ts = current
|
segment.ts = current
|
||||||
@ -822,27 +825,26 @@ func (kcp *KCP) flush() {
|
|||||||
// Update updates state (call it repeatedly, every 10ms-100ms), or you can ask
|
// 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).
|
// ikcp_check when to call it again (without ikcp_input/_send calling).
|
||||||
// 'current' - current timestamp in millisec.
|
// 'current' - current timestamp in millisec.
|
||||||
func (kcp *KCP) Update(current uint32) {
|
func (kcp *KCP) Update() {
|
||||||
var slap int32
|
var slap int32
|
||||||
|
|
||||||
kcp.current = current
|
current := currentMs()
|
||||||
|
|
||||||
if kcp.updated == 0 {
|
if kcp.updated == 0 {
|
||||||
kcp.updated = 1
|
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 {
|
if slap >= 10000 || slap < -10000 {
|
||||||
kcp.ts_flush = kcp.current
|
kcp.ts_flush = current
|
||||||
slap = 0
|
slap = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if slap >= 0 {
|
if slap >= 0 {
|
||||||
kcp.ts_flush += kcp.interval
|
kcp.ts_flush += kcp.interval
|
||||||
if _itimediff(kcp.current, kcp.ts_flush) >= 0 {
|
if _itimediff(current, kcp.ts_flush) >= 0 {
|
||||||
kcp.ts_flush = kcp.current + kcp.interval
|
kcp.ts_flush = current + kcp.interval
|
||||||
}
|
}
|
||||||
kcp.flush()
|
kcp.flush()
|
||||||
}
|
}
|
||||||
@ -855,7 +857,8 @@ func (kcp *KCP) Update(current uint32) {
|
|||||||
// Important to reduce unnacessary ikcp_update invoking. use it to
|
// Important to reduce unnacessary ikcp_update invoking. use it to
|
||||||
// schedule ikcp_update (eg. implementing an epoll-like mechanism,
|
// schedule ikcp_update (eg. implementing an epoll-like mechanism,
|
||||||
// or optimize ikcp_update when handling massive kcp connections)
|
// 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
|
ts_flush := kcp.ts_flush
|
||||||
tm_flush := int32(0x7fffffff)
|
tm_flush := int32(0x7fffffff)
|
||||||
tm_packet := int32(0x7fffffff)
|
tm_packet := int32(0x7fffffff)
|
||||||
|
332
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/sess.go
generated
vendored
332
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/sess.go
generated
vendored
@ -3,6 +3,7 @@ package kcp
|
|||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
@ -10,20 +11,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/klauspost/crc32"
|
|
||||||
|
|
||||||
"golang.org/x/net/ipv4"
|
"golang.org/x/net/ipv4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option defines extra options
|
|
||||||
type Option interface{}
|
|
||||||
|
|
||||||
// OptionWithConvId defines conversation id
|
|
||||||
type OptionWithConvId struct {
|
|
||||||
Id uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type errTimeout struct {
|
type errTimeout struct {
|
||||||
error
|
error
|
||||||
}
|
}
|
||||||
@ -38,11 +28,26 @@ const (
|
|||||||
crcSize = 4 // 4bytes packet checksum
|
crcSize = 4 // 4bytes packet checksum
|
||||||
cryptHeaderSize = nonceSize + crcSize
|
cryptHeaderSize = nonceSize + crcSize
|
||||||
mtuLimit = 2048
|
mtuLimit = 2048
|
||||||
txQueueLimit = 8192
|
rxQueueLimit = 8192
|
||||||
rxFecLimit = 8192
|
rxFECMulti = 3 // FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory
|
||||||
defaultKeepAliveInterval = 10 * time.Second
|
defaultKeepAliveInterval = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
errBrokenPipe = "broken pipe"
|
||||||
|
errInvalidOperation = "invalid operation"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
xmitBuf sync.Pool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
xmitBuf.New = func() interface{} {
|
||||||
|
return make([]byte, mtuLimit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// UDPSession defines a KCP session implemented by UDP
|
// UDPSession defines a KCP session implemented by UDP
|
||||||
UDPSession struct {
|
UDPSession struct {
|
||||||
@ -58,14 +63,13 @@ type (
|
|||||||
die chan struct{}
|
die chan struct{}
|
||||||
chReadEvent chan struct{}
|
chReadEvent chan struct{}
|
||||||
chWriteEvent chan struct{}
|
chWriteEvent chan struct{}
|
||||||
chTicker chan time.Time
|
|
||||||
chUDPOutput chan []byte
|
chUDPOutput chan []byte
|
||||||
headerSize int
|
headerSize int
|
||||||
ackNoDelay bool
|
ackNoDelay bool
|
||||||
isClosed bool
|
isClosed bool
|
||||||
keepAliveInterval time.Duration
|
keepAliveInterval int32
|
||||||
xmitBuf sync.Pool
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
updateInterval int32
|
||||||
}
|
}
|
||||||
|
|
||||||
setReadBuffer interface {
|
setReadBuffer interface {
|
||||||
@ -80,8 +84,7 @@ type (
|
|||||||
// newUDPSession create a new udp session for client or server
|
// 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 {
|
func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn net.PacketConn, remote net.Addr, block BlockCrypt) *UDPSession {
|
||||||
sess := new(UDPSession)
|
sess := new(UDPSession)
|
||||||
sess.chTicker = make(chan time.Time, 1)
|
sess.chUDPOutput = make(chan []byte)
|
||||||
sess.chUDPOutput = make(chan []byte, txQueueLimit)
|
|
||||||
sess.die = make(chan struct{})
|
sess.die = make(chan struct{})
|
||||||
sess.chReadEvent = make(chan struct{}, 1)
|
sess.chReadEvent = make(chan struct{}, 1)
|
||||||
sess.chWriteEvent = 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.keepAliveInterval = defaultKeepAliveInterval
|
||||||
sess.l = l
|
sess.l = l
|
||||||
sess.block = block
|
sess.block = block
|
||||||
sess.fec = newFEC(rxFecLimit, dataShards, parityShards)
|
sess.fec = newFEC(rxFECMulti*(dataShards+parityShards), dataShards, parityShards)
|
||||||
sess.xmitBuf.New = func() interface{} {
|
|
||||||
return make([]byte, mtuLimit)
|
|
||||||
}
|
|
||||||
// calculate header size
|
// calculate header size
|
||||||
if sess.block != nil {
|
if sess.block != nil {
|
||||||
sess.headerSize += cryptHeaderSize
|
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) {
|
sess.kcp = NewKCP(conv, func(buf []byte, size int) {
|
||||||
if size >= IKCP_OVERHEAD {
|
if size >= IKCP_OVERHEAD {
|
||||||
ext := sess.xmitBuf.Get().([]byte)[:sess.headerSize+size]
|
ext := xmitBuf.Get().([]byte)[:sess.headerSize+size]
|
||||||
copy(ext[sess.headerSize:], buf)
|
copy(ext[sess.headerSize:], buf)
|
||||||
select {
|
select {
|
||||||
case sess.chUDPOutput <- ext:
|
case sess.chUDPOutput <- ext:
|
||||||
@ -145,7 +145,7 @@ func (s *UDPSession) Read(b []byte) (n int, err error) {
|
|||||||
|
|
||||||
if s.isClosed {
|
if s.isClosed {
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
return 0, errors.New("broken pipe")
|
return 0, errors.New(errBrokenPipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.rd.IsZero() {
|
if !s.rd.IsZero() {
|
||||||
@ -169,19 +169,25 @@ func (s *UDPSession) Read(b []byte) (n int, err error) {
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout <-chan time.Time
|
var timeout *time.Timer
|
||||||
|
var c <-chan time.Time
|
||||||
if !s.rd.IsZero() {
|
if !s.rd.IsZero() {
|
||||||
delay := s.rd.Sub(time.Now())
|
delay := s.rd.Sub(time.Now())
|
||||||
timeout = time.After(delay)
|
timeout = time.NewTimer(delay)
|
||||||
|
c = timeout.C
|
||||||
}
|
}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
// wait for read event or timeout
|
// wait for read event or timeout
|
||||||
select {
|
select {
|
||||||
case <-s.chReadEvent:
|
case <-s.chReadEvent:
|
||||||
case <-timeout:
|
case <-c:
|
||||||
case <-s.die:
|
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()
|
s.mu.Lock()
|
||||||
if s.isClosed {
|
if s.isClosed {
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
return 0, errors.New("broken pipe")
|
return 0, errors.New(errBrokenPipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.wd.IsZero() {
|
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)
|
n = len(b)
|
||||||
max := s.kcp.mss << 8
|
max := s.kcp.mss << 8
|
||||||
for {
|
for {
|
||||||
@ -213,26 +219,31 @@ func (s *UDPSession) Write(b []byte) (n int, err error) {
|
|||||||
b = b[max:]
|
b = b[max:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.kcp.current = currentMs()
|
|
||||||
s.kcp.flush()
|
s.kcp.flush()
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
atomic.AddUint64(&DefaultSnmp.BytesSent, uint64(n))
|
atomic.AddUint64(&DefaultSnmp.BytesSent, uint64(n))
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout <-chan time.Time
|
var timeout *time.Timer
|
||||||
|
var c <-chan time.Time
|
||||||
if !s.wd.IsZero() {
|
if !s.wd.IsZero() {
|
||||||
delay := s.wd.Sub(time.Now())
|
delay := s.wd.Sub(time.Now())
|
||||||
timeout = time.After(delay)
|
timeout = time.NewTimer(delay)
|
||||||
|
c = timeout.C
|
||||||
}
|
}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
// wait for write event or timeout
|
// wait for write event or timeout
|
||||||
select {
|
select {
|
||||||
case <-s.chWriteEvent:
|
case <-s.chWriteEvent:
|
||||||
case <-timeout:
|
case <-c:
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if timeout != nil {
|
||||||
|
timeout.Stop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +252,7 @@ func (s *UDPSession) Close() error {
|
|||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
if s.isClosed {
|
if s.isClosed {
|
||||||
return errors.New("broken pipe")
|
return errors.New(errBrokenPipe)
|
||||||
}
|
}
|
||||||
close(s.die)
|
close(s.die)
|
||||||
s.isClosed = true
|
s.isClosed = true
|
||||||
@ -321,6 +332,7 @@ func (s *UDPSession) SetNoDelay(nodelay, interval, resend, nc int) {
|
|||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
s.kcp.NoDelay(nodelay, interval, resend, nc)
|
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
|
// 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()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
if s.l == nil {
|
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 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
|
// 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 nc.SetReadBuffer(bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return errors.New(errInvalidOperation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWriteBuffer sets the socket write buffer, no effect if it's accepted from Listener
|
// 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 nc.SetWriteBuffer(bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return errors.New(errInvalidOperation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetKeepAlive changes per-connection NAT keepalive interval; 0 to disable, default to 10s
|
// SetKeepAlive changes per-connection NAT keepalive interval; 0 to disable, default to 10s
|
||||||
func (s *UDPSession) SetKeepAlive(interval int) {
|
func (s *UDPSession) SetKeepAlive(interval int) {
|
||||||
s.mu.Lock()
|
atomic.StoreInt32(&s.keepAliveInterval, int32(interval))
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *UDPSession) outputTask() {
|
func (s *UDPSession) outputTask() {
|
||||||
@ -385,13 +387,15 @@ func (s *UDPSession) outputTask() {
|
|||||||
szOffset := fecOffset + fecHeaderSize
|
szOffset := fecOffset + fecHeaderSize
|
||||||
|
|
||||||
// fec data group
|
// fec data group
|
||||||
|
var cacheLine []byte
|
||||||
var fecGroup [][]byte
|
var fecGroup [][]byte
|
||||||
var fecCnt int
|
var fecCnt int
|
||||||
var fecMaxSize int
|
var fecMaxSize int
|
||||||
if s.fec != nil {
|
if s.fec != nil {
|
||||||
|
cacheLine = make([]byte, s.fec.shardSize*mtuLimit)
|
||||||
fecGroup = make([][]byte, s.fec.shardSize)
|
fecGroup = make([][]byte, s.fec.shardSize)
|
||||||
for k := range fecGroup {
|
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 {
|
for {
|
||||||
select {
|
select {
|
||||||
|
// receive from a synchronous channel
|
||||||
|
// buffered channel must be avoided, because of "bufferbloat"
|
||||||
case ext := <-s.chUDPOutput:
|
case ext := <-s.chUDPOutput:
|
||||||
var ecc [][]byte
|
var ecc [][]byte
|
||||||
if s.fec != nil {
|
if s.fec != nil {
|
||||||
s.fec.markData(ext[fecOffset:])
|
s.fec.markData(ext[fecOffset:])
|
||||||
// explicit size
|
// explicit size, including 2bytes size itself.
|
||||||
binary.LittleEndian.PutUint16(ext[szOffset:], uint16(len(ext[szOffset:])))
|
binary.LittleEndian.PutUint16(ext[szOffset:], uint16(len(ext[szOffset:])))
|
||||||
|
|
||||||
// copy data to fec group
|
// copy data to fec group
|
||||||
xorBytes(fecGroup[fecCnt], fecGroup[fecCnt], fecGroup[fecCnt])
|
sz := len(ext)
|
||||||
|
fecGroup[fecCnt] = fecGroup[fecCnt][:sz]
|
||||||
copy(fecGroup[fecCnt], ext)
|
copy(fecGroup[fecCnt], ext)
|
||||||
fecCnt++
|
fecCnt++
|
||||||
if len(ext) > fecMaxSize {
|
if sz > fecMaxSize {
|
||||||
fecMaxSize = len(ext)
|
fecMaxSize = sz
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate Reed-Solomon Erasure Code
|
// calculate Reed-Solomon Erasure Code
|
||||||
if fecCnt == s.fec.dataShards {
|
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)
|
ecc = s.fec.calcECC(fecGroup, szOffset, fecMaxSize)
|
||||||
for k := range ecc {
|
for k := range ecc {
|
||||||
s.fec.markFEC(ecc[k][fecOffset:])
|
s.fec.markFEC(ecc[k][fecOffset:])
|
||||||
@ -445,39 +457,37 @@ func (s *UDPSession) outputTask() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if rand.Intn(100) < 80 {
|
nbytes := 0
|
||||||
if n, err := s.writeTo(ext, s.remote); err == nil {
|
nsegs := 0
|
||||||
atomic.AddUint64(&DefaultSnmp.OutSegs, 1)
|
// if mrand.Intn(100) < 50 {
|
||||||
atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(n))
|
if n, err := s.conn.WriteTo(ext, s.remote); err == nil {
|
||||||
|
nbytes += n
|
||||||
|
nsegs++
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if ecc != nil {
|
if ecc != nil {
|
||||||
for k := range ecc {
|
for k := range ecc {
|
||||||
if n, err := s.writeTo(ecc[k], s.remote); err == nil {
|
if n, err := s.conn.WriteTo(ecc[k], s.remote); err == nil {
|
||||||
atomic.AddUint64(&DefaultSnmp.OutSegs, 1)
|
nbytes += n
|
||||||
atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(n))
|
nsegs++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xorBytes(ext, ext, ext)
|
atomic.AddUint64(&DefaultSnmp.OutSegs, uint64(nsegs))
|
||||||
s.xmitBuf.Put(ext)
|
atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(nbytes))
|
||||||
|
xmitBuf.Put(ext)
|
||||||
case <-ticker.C: // NAT keep-alive
|
case <-ticker.C: // NAT keep-alive
|
||||||
if len(s.chUDPOutput) == 0 {
|
interval := time.Duration(atomic.LoadInt32(&s.keepAliveInterval)) * time.Second
|
||||||
s.mu.Lock()
|
|
||||||
interval := s.keepAliveInterval
|
|
||||||
s.mu.Unlock()
|
|
||||||
if interval > 0 && time.Now().After(lastPing.Add(interval)) {
|
if interval > 0 && time.Now().After(lastPing.Add(interval)) {
|
||||||
buf := make([]byte, 2)
|
var rnd uint16
|
||||||
io.ReadFull(rand.Reader, buf)
|
binary.Read(rand.Reader, binary.LittleEndian, &rnd)
|
||||||
rnd := int(binary.LittleEndian.Uint16(buf))
|
sz := int(rnd)%(IKCP_MTU_DEF-s.headerSize-IKCP_OVERHEAD) + s.headerSize + IKCP_OVERHEAD
|
||||||
sz := rnd%(IKCP_MTU_DEF-s.headerSize-IKCP_OVERHEAD) + s.headerSize + IKCP_OVERHEAD
|
ping := make([]byte, sz) // randomized ping packet
|
||||||
ping := make([]byte, sz)
|
|
||||||
io.ReadFull(rand.Reader, ping)
|
io.ReadFull(rand.Reader, ping)
|
||||||
s.writeTo(ping, s.remote)
|
s.conn.WriteTo(ping, s.remote)
|
||||||
lastPing = time.Now()
|
lastPing = time.Now()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -486,25 +496,18 @@ func (s *UDPSession) outputTask() {
|
|||||||
|
|
||||||
// kcp update, input loop
|
// kcp update, input loop
|
||||||
func (s *UDPSession) updateTask() {
|
func (s *UDPSession) updateTask() {
|
||||||
var tc <-chan time.Time
|
tc := time.After(time.Duration(atomic.LoadInt32(&s.updateInterval)) * time.Millisecond)
|
||||||
if s.l == nil { // client
|
|
||||||
ticker := time.NewTicker(10 * time.Millisecond)
|
|
||||||
tc = ticker.C
|
|
||||||
defer ticker.Stop()
|
|
||||||
} else {
|
|
||||||
tc = s.chTicker
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-tc:
|
case <-tc:
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
current := currentMs()
|
s.kcp.flush()
|
||||||
s.kcp.Update(current)
|
if s.kcp.WaitSnd() < int(s.kcp.snd_wnd) {
|
||||||
if s.kcp.WaitSnd() < 2*int(s.kcp.snd_wnd) {
|
|
||||||
s.notifyWriteEvent()
|
s.notifyWriteEvent()
|
||||||
}
|
}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
tc = time.After(time.Duration(atomic.LoadInt32(&s.updateInterval)) * time.Millisecond)
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
if s.l != nil { // has listener
|
if s.l != nil { // has listener
|
||||||
select {
|
select {
|
||||||
@ -537,58 +540,84 @@ func (s *UDPSession) notifyWriteEvent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *UDPSession) kcpInput(data []byte) {
|
func (s *UDPSession) kcpInput(data []byte) {
|
||||||
current := currentMs()
|
var kcpInErrors, fecErrs, fecRecovered, fecSegs uint64
|
||||||
|
|
||||||
if s.fec != nil {
|
if s.fec != nil {
|
||||||
f := s.fec.decode(data)
|
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 == typeData || f.flag == typeFEC {
|
||||||
if f.flag == typeFEC {
|
if f.flag == typeFEC {
|
||||||
atomic.AddUint64(&DefaultSnmp.FECSegs, 1)
|
fecSegs++
|
||||||
}
|
}
|
||||||
|
|
||||||
if recovers := s.fec.input(f); recovers != nil {
|
if recovers := s.fec.input(f); recovers != nil {
|
||||||
s.mu.Lock()
|
for _, r := range recovers {
|
||||||
s.kcp.current = current
|
if len(r) >= 2 { // must be larger than 2bytes
|
||||||
for k := range recovers {
|
sz := binary.LittleEndian.Uint16(r)
|
||||||
sz := binary.LittleEndian.Uint16(recovers[k])
|
if int(sz) <= len(r) && sz >= 2 {
|
||||||
if int(sz) <= len(recovers[k]) && sz >= 2 {
|
if ret := s.kcp.Input(r[2:sz], false); ret == 0 {
|
||||||
s.kcp.Input(recovers[k][2:sz], false)
|
fecRecovered++
|
||||||
} else {
|
} else {
|
||||||
atomic.AddUint64(&DefaultSnmp.FECErrs, 1)
|
kcpInErrors++
|
||||||
}
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.mu.Lock()
|
fecErrs++
|
||||||
s.kcp.current = current
|
}
|
||||||
s.kcp.Input(data, true)
|
} else {
|
||||||
s.mu.Unlock()
|
fecErrs++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify reader
|
// notify reader
|
||||||
s.mu.Lock()
|
|
||||||
if n := s.kcp.PeekSize(); n > 0 {
|
if n := s.kcp.PeekSize(); n > 0 {
|
||||||
s.notifyReadEvent()
|
s.notifyReadEvent()
|
||||||
}
|
}
|
||||||
if s.ackNoDelay {
|
if s.ackNoDelay {
|
||||||
s.kcp.current = current
|
|
||||||
s.kcp.flush()
|
s.kcp.flush()
|
||||||
}
|
}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
} else {
|
||||||
|
s.mu.Lock()
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
atomic.AddUint64(&DefaultSnmp.InSegs, 1)
|
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) {
|
func (s *UDPSession) receiver(ch chan []byte) {
|
||||||
for {
|
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 {
|
if n, _, err := s.conn.ReadFrom(data); err == nil && n >= s.headerSize+IKCP_OVERHEAD {
|
||||||
select {
|
select {
|
||||||
case ch <- data[:n]:
|
case ch <- data[:n]:
|
||||||
@ -604,7 +633,7 @@ func (s *UDPSession) receiver(ch chan []byte) {
|
|||||||
|
|
||||||
// read loop for client session
|
// read loop for client session
|
||||||
func (s *UDPSession) readLoop() {
|
func (s *UDPSession) readLoop() {
|
||||||
chPacket := make(chan []byte, txQueueLimit)
|
chPacket := make(chan []byte, rxQueueLimit)
|
||||||
go s.receiver(chPacket)
|
go s.receiver(chPacket)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -629,8 +658,7 @@ func (s *UDPSession) readLoop() {
|
|||||||
if dataValid {
|
if dataValid {
|
||||||
s.kcpInput(data)
|
s.kcpInput(data)
|
||||||
}
|
}
|
||||||
xorBytes(raw, raw, raw)
|
xmitBuf.Put(raw)
|
||||||
s.xmitBuf.Put(raw)
|
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -662,10 +690,8 @@ type (
|
|||||||
|
|
||||||
// monitor incoming data for all connections of server
|
// monitor incoming data for all connections of server
|
||||||
func (l *Listener) monitor() {
|
func (l *Listener) monitor() {
|
||||||
chPacket := make(chan packet, txQueueLimit)
|
chPacket := make(chan packet, rxQueueLimit)
|
||||||
go l.receiver(chPacket)
|
go l.receiver(chPacket)
|
||||||
ticker := time.NewTicker(10 * time.Millisecond)
|
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case p := <-chPacket:
|
case p := <-chPacket:
|
||||||
@ -715,20 +741,11 @@ func (l *Listener) monitor() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xorBytes(raw, raw, raw)
|
|
||||||
l.rxbuf.Put(raw)
|
l.rxbuf.Put(raw)
|
||||||
case deadlink := <-l.chDeadlinks:
|
case deadlink := <-l.chDeadlinks:
|
||||||
delete(l.sessions, deadlink.String())
|
delete(l.sessions, deadlink.String())
|
||||||
case <-l.die:
|
case <-l.die:
|
||||||
return
|
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 {
|
if nc, ok := l.conn.(setReadBuffer); ok {
|
||||||
return nc.SetReadBuffer(bytes)
|
return nc.SetReadBuffer(bytes)
|
||||||
}
|
}
|
||||||
return nil
|
return errors.New(errInvalidOperation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWriteBuffer sets the socket write buffer for the Listener
|
// 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 {
|
if nc, ok := l.conn.(setWriteBuffer); ok {
|
||||||
return nc.SetWriteBuffer(bytes)
|
return nc.SetWriteBuffer(bytes)
|
||||||
}
|
}
|
||||||
return nil
|
return errors.New(errInvalidOperation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDSCP sets the 6bit DSCP field of IP header
|
// 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 {
|
if nc, ok := l.conn.(net.Conn); ok {
|
||||||
return ipv4.NewConn(nc).SetTOS(dscp << 2)
|
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.
|
// 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:
|
case c := <-l.chAccepts:
|
||||||
return c, nil
|
return c, nil
|
||||||
case <-l.die:
|
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",
|
// 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)
|
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 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 := new(Listener)
|
||||||
l.conn = conn
|
l.conn = conn
|
||||||
l.sessions = make(map[string]*UDPSession)
|
l.sessions = make(map[string]*UDPSession)
|
||||||
@ -848,7 +870,7 @@ func ListenWithOptions(laddr string, block BlockCrypt, dataShards, parityShards
|
|||||||
l.dataShards = dataShards
|
l.dataShards = dataShards
|
||||||
l.parityShards = parityShards
|
l.parityShards = parityShards
|
||||||
l.block = block
|
l.block = block
|
||||||
l.fec = newFEC(rxFecLimit, dataShards, parityShards)
|
l.fec = newFEC(rxFECMulti*(dataShards+parityShards), dataShards, parityShards)
|
||||||
l.rxbuf.New = func() interface{} {
|
l.rxbuf.New = func() interface{} {
|
||||||
return make([]byte, mtuLimit)
|
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"
|
// 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)
|
return DialWithOptions(raddr, nil, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialWithOptions connects to the remote address "raddr" on the network "udp" with packet encryption
|
// 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)
|
udpaddr, err := net.ResolveUDPAddr("udp", raddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "net.ResolveUDPAddr")
|
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")
|
return nil, errors.Wrap(err, "net.DialUDP")
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := make([]byte, 4)
|
return NewConn(raddr, block, dataShards, parityShards, &ConnectedUDPConn{udpconn, udpconn})
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
func currentMs() uint32 {
|
||||||
return uint32(time.Now().UnixNano() / int64(time.Millisecond))
|
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)
|
||||||
|
}
|
||||||
|
110
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/snmp.go
generated
vendored
110
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/snmp.go
generated
vendored
@ -1,34 +1,95 @@
|
|||||||
package kcp
|
package kcp
|
||||||
|
|
||||||
import "sync/atomic"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
// Snmp defines network statistics indicator
|
// Snmp defines network statistics indicator
|
||||||
type Snmp struct {
|
type Snmp struct {
|
||||||
BytesSent uint64 // payload bytes sent
|
BytesSent uint64 // raw bytes sent
|
||||||
BytesReceived uint64
|
BytesReceived uint64
|
||||||
MaxConn uint64
|
MaxConn uint64
|
||||||
ActiveOpens uint64
|
ActiveOpens uint64
|
||||||
PassiveOpens uint64
|
PassiveOpens uint64
|
||||||
CurrEstab uint64
|
CurrEstab uint64 // count of connections for now
|
||||||
InErrs uint64
|
InErrs uint64 // udp read errors
|
||||||
InCsumErrors uint64 // checksum errors
|
InCsumErrors uint64 // checksum errors from CRC32
|
||||||
|
KCPInErrors uint64 // packet iput errors from kcp
|
||||||
InSegs uint64
|
InSegs uint64
|
||||||
OutSegs uint64
|
OutSegs uint64
|
||||||
|
InBytes uint64 // udp bytes received
|
||||||
OutBytes uint64 // udp bytes sent
|
OutBytes uint64 // udp bytes sent
|
||||||
RetransSegs uint64
|
RetransSegs uint64
|
||||||
FastRetransSegs uint64
|
FastRetransSegs uint64
|
||||||
EarlyRetransSegs uint64
|
EarlyRetransSegs uint64
|
||||||
LostSegs uint64
|
LostSegs uint64 // number of segs infered as lost
|
||||||
RepeatSegs uint64
|
RepeatSegs uint64 // number of segs duplicated
|
||||||
FECRecovered uint64
|
FECRecovered uint64 // correct packets recovered from FEC
|
||||||
FECErrs uint64
|
FECErrs uint64 // incorrect packets recovered from FEC
|
||||||
FECSegs uint64 // fec segments received
|
FECSegs uint64 // FEC segments received
|
||||||
|
FECShortShards uint64 // number of data shards that's not enough for recovery
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSnmp() *Snmp {
|
func newSnmp() *Snmp {
|
||||||
return new(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
|
// Copy make a copy of current snmp snapshot
|
||||||
func (s *Snmp) Copy() *Snmp {
|
func (s *Snmp) Copy() *Snmp {
|
||||||
d := newSnmp()
|
d := newSnmp()
|
||||||
@ -40,8 +101,10 @@ func (s *Snmp) Copy() *Snmp {
|
|||||||
d.CurrEstab = atomic.LoadUint64(&s.CurrEstab)
|
d.CurrEstab = atomic.LoadUint64(&s.CurrEstab)
|
||||||
d.InErrs = atomic.LoadUint64(&s.InErrs)
|
d.InErrs = atomic.LoadUint64(&s.InErrs)
|
||||||
d.InCsumErrors = atomic.LoadUint64(&s.InCsumErrors)
|
d.InCsumErrors = atomic.LoadUint64(&s.InCsumErrors)
|
||||||
|
d.KCPInErrors = atomic.LoadUint64(&s.KCPInErrors)
|
||||||
d.InSegs = atomic.LoadUint64(&s.InSegs)
|
d.InSegs = atomic.LoadUint64(&s.InSegs)
|
||||||
d.OutSegs = atomic.LoadUint64(&s.OutSegs)
|
d.OutSegs = atomic.LoadUint64(&s.OutSegs)
|
||||||
|
d.InBytes = atomic.LoadUint64(&s.InBytes)
|
||||||
d.OutBytes = atomic.LoadUint64(&s.OutBytes)
|
d.OutBytes = atomic.LoadUint64(&s.OutBytes)
|
||||||
d.RetransSegs = atomic.LoadUint64(&s.RetransSegs)
|
d.RetransSegs = atomic.LoadUint64(&s.RetransSegs)
|
||||||
d.FastRetransSegs = atomic.LoadUint64(&s.FastRetransSegs)
|
d.FastRetransSegs = atomic.LoadUint64(&s.FastRetransSegs)
|
||||||
@ -51,9 +114,36 @@ func (s *Snmp) Copy() *Snmp {
|
|||||||
d.FECSegs = atomic.LoadUint64(&s.FECSegs)
|
d.FECSegs = atomic.LoadUint64(&s.FECSegs)
|
||||||
d.FECErrs = atomic.LoadUint64(&s.FECErrs)
|
d.FECErrs = atomic.LoadUint64(&s.FECErrs)
|
||||||
d.FECRecovered = atomic.LoadUint64(&s.FECRecovered)
|
d.FECRecovered = atomic.LoadUint64(&s.FECRecovered)
|
||||||
|
d.FECShortShards = atomic.LoadUint64(&s.FECShortShards)
|
||||||
return d
|
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
|
// DefaultSnmp is the global KCP connection statistics collector
|
||||||
var DefaultSnmp *Snmp
|
var DefaultSnmp *Snmp
|
||||||
|
|
||||||
|
38
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/xor.go
generated
vendored
38
cmd/gost/vendor/gopkg.in/xtaci/kcp-go.v2/xor.go
generated
vendored
@ -44,15 +44,18 @@ func safeXORBytes(dst, a, b []byte) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := ex; i < n; i += 8 {
|
for i := ex; i < n; i += 8 {
|
||||||
dst[i] = a[i] ^ b[i]
|
_dst := dst[i : i+8]
|
||||||
dst[i+1] = a[i+1] ^ b[i+1]
|
_a := a[i : i+8]
|
||||||
dst[i+2] = a[i+2] ^ b[i+2]
|
_b := b[i : i+8]
|
||||||
dst[i+3] = a[i+3] ^ b[i+3]
|
_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[4] = _a[4] ^ _b[4]
|
||||||
dst[i+5] = a[i+5] ^ b[i+5]
|
_dst[5] = _a[5] ^ _b[5]
|
||||||
dst[i+6] = a[i+6] ^ b[i+6]
|
_dst[6] = _a[6] ^ _b[6]
|
||||||
dst[i+7] = a[i+7] ^ b[i+7]
|
_dst[7] = _a[7] ^ _b[7]
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
@ -85,14 +88,17 @@ func fastXORWords(dst, a, b []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := ex; i < n; i += 8 {
|
for i := ex; i < n; i += 8 {
|
||||||
dw[i] = aw[i] ^ bw[i]
|
_dw := dw[i : i+8]
|
||||||
dw[i+1] = aw[i+1] ^ bw[i+1]
|
_aw := aw[i : i+8]
|
||||||
dw[i+2] = aw[i+2] ^ bw[i+2]
|
_bw := bw[i : i+8]
|
||||||
dw[i+3] = aw[i+3] ^ bw[i+3]
|
_dw[0] = _aw[0] ^ _bw[0]
|
||||||
dw[i+4] = aw[i+4] ^ bw[i+4]
|
_dw[1] = _aw[1] ^ _bw[1]
|
||||||
dw[i+5] = aw[i+5] ^ bw[i+5]
|
_dw[2] = _aw[2] ^ _bw[2]
|
||||||
dw[i+6] = aw[i+6] ^ bw[i+6]
|
_dw[3] = _aw[3] ^ _bw[3]
|
||||||
dw[i+7] = aw[i+7] ^ bw[i+7]
|
_dw[4] = _aw[4] ^ _bw[4]
|
||||||
|
_dw[5] = _aw[5] ^ _bw[5]
|
||||||
|
_dw[6] = _aw[6] ^ _bw[6]
|
||||||
|
_dw[7] = _aw[7] ^ _bw[7]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
cmd/gost/vendor/gopkg.in/xtaci/smux.v1/README.md
generated
vendored
4
cmd/gost/vendor/gopkg.in/xtaci/smux.v1/README.md
generated
vendored
@ -62,7 +62,7 @@ func client() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream implements net.Conn
|
// Stream implements io.ReadWriteCloser
|
||||||
stream.Write([]byte("ping"))
|
stream.Write([]byte("ping"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,4 +94,4 @@ func server() {
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Beta
|
Stable
|
||||||
|
109
cmd/gost/vendor/gopkg.in/xtaci/smux.v1/session.go
generated
vendored
109
cmd/gost/vendor/gopkg.in/xtaci/smux.v1/session.go
generated
vendored
@ -16,10 +16,19 @@ const (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
errBrokenPipe = "broken pipe"
|
errBrokenPipe = "broken pipe"
|
||||||
errConnReset = "connection reset by peer"
|
|
||||||
errInvalidProtocol = "invalid protocol version"
|
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
|
// Session defines a multiplexed connection for streams
|
||||||
type Session struct {
|
type Session struct {
|
||||||
conn io.ReadWriteCloser
|
conn io.ReadWriteCloser
|
||||||
@ -38,7 +47,12 @@ type Session struct {
|
|||||||
dieLock sync.Mutex
|
dieLock sync.Mutex
|
||||||
chAccepts chan *Stream
|
chAccepts chan *Stream
|
||||||
|
|
||||||
|
xmitPool sync.Pool
|
||||||
dataReady int32 // flag data has arrived
|
dataReady int32 // flag data has arrived
|
||||||
|
|
||||||
|
deadline atomic.Value
|
||||||
|
|
||||||
|
writes chan writeRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session {
|
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.chAccepts = make(chan *Stream, defaultAcceptBacklog)
|
||||||
s.bucket = int32(config.MaxReceiveBuffer)
|
s.bucket = int32(config.MaxReceiveBuffer)
|
||||||
s.bucketCond = sync.NewCond(&sync.Mutex{})
|
s.bucketCond = sync.NewCond(&sync.Mutex{})
|
||||||
|
s.xmitPool.New = func() interface{} {
|
||||||
|
return make([]byte, (1<<16)+headerSize)
|
||||||
|
}
|
||||||
|
s.writes = make(chan writeRequest)
|
||||||
|
|
||||||
if client {
|
if client {
|
||||||
s.nextStreamID = 1
|
s.nextStreamID = 1
|
||||||
} else {
|
} else {
|
||||||
s.nextStreamID = 2
|
s.nextStreamID = 2
|
||||||
}
|
}
|
||||||
go s.recvLoop()
|
go s.recvLoop()
|
||||||
|
go s.sendLoop()
|
||||||
go s.keepalive()
|
go s.keepalive()
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@ -82,9 +102,17 @@ func (s *Session) OpenStream() (*Stream, error) {
|
|||||||
// AcceptStream is used to block until the next available stream
|
// AcceptStream is used to block until the next available stream
|
||||||
// is ready to be accepted.
|
// is ready to be accepted.
|
||||||
func (s *Session) AcceptStream() (*Stream, error) {
|
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 {
|
select {
|
||||||
case stream := <-s.chAccepts:
|
case stream := <-s.chAccepts:
|
||||||
return stream, nil
|
return stream, nil
|
||||||
|
case <-deadline:
|
||||||
|
return nil, errTimeout
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
return nil, errors.New(errBrokenPipe)
|
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.
|
// Close is used to close the session and all streams.
|
||||||
func (s *Session) Close() (err error) {
|
func (s *Session) Close() (err error) {
|
||||||
s.dieLock.Lock()
|
s.dieLock.Lock()
|
||||||
defer s.dieLock.Unlock()
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
|
s.dieLock.Unlock()
|
||||||
return errors.New(errBrokenPipe)
|
return errors.New(errBrokenPipe)
|
||||||
default:
|
default:
|
||||||
close(s.die)
|
close(s.die)
|
||||||
|
s.dieLock.Unlock()
|
||||||
s.streamLock.Lock()
|
s.streamLock.Lock()
|
||||||
for k := range s.streams {
|
for k := range s.streams {
|
||||||
s.streams[k].sessionClose()
|
s.streams[k].sessionClose()
|
||||||
@ -130,6 +159,13 @@ func (s *Session) NumStreams() int {
|
|||||||
return len(s.streams)
|
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
|
// notify the session that a stream has closed
|
||||||
func (s *Session) streamClosed(sid uint32) {
|
func (s *Session) streamClosed(sid uint32) {
|
||||||
s.streamLock.Lock()
|
s.streamLock.Lock()
|
||||||
@ -144,9 +180,12 @@ func (s *Session) streamClosed(sid uint32) {
|
|||||||
|
|
||||||
// returnTokens is called by stream to return token after read
|
// returnTokens is called by stream to return token after read
|
||||||
func (s *Session) returnTokens(n int) {
|
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()
|
s.bucketCond.Signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// session read a frame from underlying connection
|
// 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
|
// writeFrame writes the frame to the underlying connection
|
||||||
// and returns the number of bytes written if successful
|
// and returns the number of bytes written if successful
|
||||||
func (s *Session) writeFrame(f Frame) (n int, err error) {
|
func (s *Session) writeFrame(f Frame) (n int, err error) {
|
||||||
buf := make([]byte, headerSize+len(f.data))
|
req := writeRequest{
|
||||||
buf[0] = f.ver
|
frame: f,
|
||||||
buf[1] = f.cmd
|
result: make(chan writeResult, 1),
|
||||||
binary.LittleEndian.PutUint16(buf[2:], uint16(len(f.data)))
|
}
|
||||||
binary.LittleEndian.PutUint32(buf[4:], f.sid)
|
select {
|
||||||
copy(buf[headerSize:], f.data)
|
case <-s.die:
|
||||||
|
return 0, errors.New(errBrokenPipe)
|
||||||
s.writeLock.Lock()
|
case s.writes <- req:
|
||||||
n, err = s.conn.Write(buf)
|
|
||||||
s.writeLock.Unlock()
|
|
||||||
return n, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeBinary writes the byte slice to the underlying connection
|
result := <-req.result
|
||||||
func (s *Session) writeBinary(bts []byte) (n int, err error) {
|
return result.n, result.err
|
||||||
s.writeLock.Lock()
|
|
||||||
n, err = s.conn.Write(bts)
|
|
||||||
s.writeLock.Unlock()
|
|
||||||
return n, err
|
|
||||||
}
|
}
|
||||||
|
124
cmd/gost/vendor/gopkg.in/xtaci/smux.v1/stream.go
generated
vendored
124
cmd/gost/vendor/gopkg.in/xtaci/smux.v1/stream.go
generated
vendored
@ -2,9 +2,11 @@ package smux
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"io"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -20,6 +22,8 @@ type Stream struct {
|
|||||||
chReadEvent chan struct{} // notify a read event
|
chReadEvent chan struct{} // notify a read event
|
||||||
die chan struct{} // flag the stream has closed
|
die chan struct{} // flag the stream has closed
|
||||||
dieLock sync.Mutex
|
dieLock sync.Mutex
|
||||||
|
readDeadline atomic.Value
|
||||||
|
writeDeadline atomic.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// newStream initiates a Stream struct
|
// newStream initiates a Stream struct
|
||||||
@ -35,10 +39,19 @@ func newStream(id uint32, frameSize int, sess *Session) *Stream {
|
|||||||
|
|
||||||
// Read implements io.ReadWriteCloser
|
// Read implements io.ReadWriteCloser
|
||||||
func (s *Stream) Read(b []byte) (n int, err error) {
|
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:
|
READ:
|
||||||
select {
|
select {
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
return 0, errors.New(errBrokenPipe)
|
return 0, errors.New(errBrokenPipe)
|
||||||
|
case <-deadline:
|
||||||
|
return n, errTimeout
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,12 +64,14 @@ READ:
|
|||||||
return n, nil
|
return n, nil
|
||||||
} else if atomic.LoadInt32(&s.rstflag) == 1 {
|
} else if atomic.LoadInt32(&s.rstflag) == 1 {
|
||||||
_ = s.Close()
|
_ = s.Close()
|
||||||
return 0, errors.New(errConnReset)
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-s.chReadEvent:
|
case <-s.chReadEvent:
|
||||||
goto READ
|
goto READ
|
||||||
|
case <-deadline:
|
||||||
|
return n, errTimeout
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
return 0, errors.New(errBrokenPipe)
|
return 0, errors.New(errBrokenPipe)
|
||||||
}
|
}
|
||||||
@ -64,6 +79,13 @@ READ:
|
|||||||
|
|
||||||
// Write implements io.ReadWriteCloser
|
// Write implements io.ReadWriteCloser
|
||||||
func (s *Stream) Write(b []byte) (n int, err error) {
|
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 {
|
select {
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
return 0, errors.New(errBrokenPipe)
|
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)
|
frames := s.split(b, cmdPSH, s.id)
|
||||||
// preallocate buffer
|
sent := 0
|
||||||
buffer := make([]byte, len(frames)*headerSize+len(b))
|
|
||||||
bts := buffer
|
|
||||||
|
|
||||||
// combine frames into a large blob
|
|
||||||
for k := range frames {
|
for k := range frames {
|
||||||
bts[0] = version
|
req := writeRequest{
|
||||||
bts[1] = frames[k].cmd
|
frame: frames[k],
|
||||||
binary.LittleEndian.PutUint16(bts[2:], uint16(len(frames[k].data)))
|
result: make(chan writeResult, 1),
|
||||||
binary.LittleEndian.PutUint32(bts[4:], frames[k].sid)
|
|
||||||
copy(bts[headerSize:], frames[k].data)
|
|
||||||
bts = bts[len(frames[k].data)+headerSize:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = s.sess.writeBinary(buffer); err != nil {
|
select {
|
||||||
return 0, err
|
case s.sess.writes <- req:
|
||||||
|
case <-s.die:
|
||||||
|
return sent, errors.New(errBrokenPipe)
|
||||||
|
case <-deadline:
|
||||||
|
return sent, errTimeout
|
||||||
}
|
}
|
||||||
return len(b), nil
|
|
||||||
|
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 sent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements io.ReadWriteCloser
|
// Close implements io.ReadWriteCloser
|
||||||
func (s *Stream) Close() error {
|
func (s *Stream) Close() error {
|
||||||
s.dieLock.Lock()
|
s.dieLock.Lock()
|
||||||
defer s.dieLock.Unlock()
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-s.die:
|
case <-s.die:
|
||||||
|
s.dieLock.Unlock()
|
||||||
return errors.New(errBrokenPipe)
|
return errors.New(errBrokenPipe)
|
||||||
default:
|
default:
|
||||||
close(s.die)
|
close(s.die)
|
||||||
|
s.dieLock.Unlock()
|
||||||
s.sess.streamClosed(s.id)
|
s.sess.streamClosed(s.id)
|
||||||
_, err := s.sess.writeFrame(newFrame(cmdRST, s.id))
|
_, err := s.sess.writeFrame(newFrame(cmdRST, s.id))
|
||||||
return err
|
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
|
// session closes the stream
|
||||||
func (s *Stream) sessionClose() {
|
func (s *Stream) sessionClose() {
|
||||||
s.dieLock.Lock()
|
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
|
// pushBytes a slice into buffer
|
||||||
func (s *Stream) pushBytes(p []byte) {
|
func (s *Stream) pushBytes(p []byte) {
|
||||||
s.bufferLock.Lock()
|
s.bufferLock.Lock()
|
||||||
@ -164,3 +246,11 @@ func (s *Stream) notifyReadEvent() {
|
|||||||
func (s *Stream) markRST() {
|
func (s *Stream) markRST() {
|
||||||
atomic.StoreInt32(&s.rstflag, 1)
|
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 }
|
||||||
|
24
cmd/gost/vendor/vendor.json
vendored
24
cmd/gost/vendor/vendor.json
vendored
@ -8,12 +8,6 @@
|
|||||||
"revision": "c91e78db502ff629614837aacb7aa4efa61c651a",
|
"revision": "c91e78db502ff629614837aacb7aa4efa61c651a",
|
||||||
"revisionTime": "2016-04-30T09:49:23Z"
|
"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=",
|
"checksumSHA1": "aIhLeVAIrsjs63CwqmU3+GU8yT4=",
|
||||||
"path": "github.com/ginuerzh/gosocks4",
|
"path": "github.com/ginuerzh/gosocks4",
|
||||||
@ -68,12 +62,6 @@
|
|||||||
"revision": "09cded8978dc9e80714c4d85b0322337b0a1e5e0",
|
"revision": "09cded8978dc9e80714c4d85b0322337b0a1e5e0",
|
||||||
"revisionTime": "2016-03-02T07:53:16Z"
|
"revisionTime": "2016-03-02T07:53:16Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"checksumSHA1": "BM6ZlNJmtKy3GBoWwg2X55gnZ4A=",
|
|
||||||
"path": "github.com/klauspost/crc32",
|
|
||||||
"revision": "cb6bfca970f6908083f26f39a79009d608efd5cd",
|
|
||||||
"revisionTime": "2016-10-16T15:41:25Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"checksumSHA1": "dwSGkUfh3A2h0VkXndzBX/27hVc=",
|
"checksumSHA1": "dwSGkUfh3A2h0VkXndzBX/27hVc=",
|
||||||
"path": "github.com/klauspost/reedsolomon",
|
"path": "github.com/klauspost/reedsolomon",
|
||||||
@ -291,16 +279,16 @@
|
|||||||
"revisionTime": "2016-12-15T22:53:35Z"
|
"revisionTime": "2016-12-15T22:53:35Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "nkIlj9QTxHQ78Vb+VgjhXZ4rZ3E=",
|
"checksumSHA1": "SbBORpjEg3VfPfdSrW82pa3f9Io=",
|
||||||
"path": "gopkg.in/xtaci/kcp-go.v2",
|
"path": "gopkg.in/xtaci/kcp-go.v2",
|
||||||
"revision": "6610d527ea5c4890cf593796ff8ff1f10486bb68",
|
"revision": "6da5044c742f24f05b00db9214b57b2ac943c9ab",
|
||||||
"revisionTime": "2016-09-08T14:44:41Z"
|
"revisionTime": "2017-01-20T08:43:10Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "aIqXwA82JxLOXcgmuVSgcRqdJvU=",
|
"checksumSHA1": "EutBuLS2elfcDCMifXNMGj9farQ=",
|
||||||
"path": "gopkg.in/xtaci/smux.v1",
|
"path": "gopkg.in/xtaci/smux.v1",
|
||||||
"revision": "9f2b528a60917e6446273926f4c676cac759d2b0",
|
"revision": "427dd804ce9fb0a9e7b27a628f68a124fb0d67a6",
|
||||||
"revisionTime": "2016-09-22T10:26:45Z"
|
"revisionTime": "2016-11-29T15:03:00Z"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rootPath": "github.com/ginuerzh/gost/cmd/gost"
|
"rootPath": "github.com/ginuerzh/gost/cmd/gost"
|
||||||
|
Loading…
Reference in New Issue
Block a user