mirror of
https://github.com/xtaci/kcptun.git
synced 2024-04-21 12:32:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7167b5859 | ||
|
|
b63eeb6301 | ||
|
|
5b5c094e4b | ||
|
|
c4bd77cf28 | ||
|
|
94c9cacf4f | ||
|
|
9a5b31b470 | ||
|
|
07ad03fecf | ||
|
|
2225d258cb | ||
|
|
e9316f7be4 | ||
|
|
9ac04cd24d | ||
|
|
76c4d231f2 | ||
|
|
160b68cbc5 | ||
|
|
212504f6c2 | ||
|
|
114cd97025 | ||
|
|
b2be91cdb5 |
@@ -106,7 +106,7 @@ All precompiled releases are genereated from `build-release.sh` script.
|
||||
|
||||
> eg: `-mode fast3`
|
||||
|
||||
> Aggresiveness/Responsiveness on retransmission for embeded modes are:
|
||||
> Aggresiveness/Responsiveness on retransmission for embedded modes are:
|
||||
|
||||
> *fast3 > fast2 > fast > normal > default*
|
||||
|
||||
@@ -152,7 +152,7 @@ GLOBAL OPTIONS:
|
||||
--mode value profiles: fast3, fast2, fast, normal, manual (default: "fast")
|
||||
--conn value set num of UDP connections to server (default: 1)
|
||||
--autoexpire value set auto expiration time(in seconds) for a single UDP connection, 0 to disable (default: 0)
|
||||
--scavengettl value set how long an expired connection can live(in sec), -1 to disable (default: 600)
|
||||
--scavengettl value set how long an expired connection can live (in seconds) (default: 600)
|
||||
--mtu value set maximum transmission unit for UDP packets (default: 1350)
|
||||
--sndwnd value set send window size(num of packets) (default: 128)
|
||||
--rcvwnd value set receive window size(num of packets) (default: 512)
|
||||
@@ -224,8 +224,6 @@ It is able to detect and correct multiple symbol errors. By adding t check symbo
|
||||
|
||||

|
||||
|
||||
Setting parameters of RS-Code with ```-datashard m -parityshard n``` on **BOTH** KCP Client & KCP Server **MUST** be **IDENTICAL**.
|
||||
|
||||
#### DSCP
|
||||
|
||||
Differentiated services or DiffServ is a computer networking architecture that specifies a simple, scalable and coarse-grained mechanism for classifying and managing network traffic and providing quality of service (QoS) on modern IP networks. DiffServ can, for example, be used to provide low-latency to critical network traffic such as voice or streaming media while providing simple best-effort service to non-critical services such as web traffic or file transfers.
|
||||
@@ -293,7 +291,7 @@ Reference: https://blog.golang.org/go15gc
|
||||
Primary memory allocation are done from a global buffer pool *xmit.Buf*, in kcp-go, when we need to allocate some bytes, we can get from that pool, and a *fixed-capacity* 1500 bytes(mtuLimit) will be returned, the *rx queue*, *tx queue* and *fec queue* all receive bytes from there, and they will return the bytes to the pool after using to prevent *unnecessary zer0ing* of bytes.
|
||||
The pool mechanism maintained a *high watermark* for slice objects, these *in-flight* objects from the pool will survive from the perodical garbage collection, meanwhile the pool kept the ability to return the memory to runtime if in idle, `-sndwnd`,`-rcvwnd`,`-ds`, `-ps`, these parameters affect this *high watermark*, the larger the value, the bigger the memory consumption will be.
|
||||
|
||||
`-smuxbuf` also affects the maximum memory consumption, this parameter maintains a subtle balance between *concurrency* and *resource*, you can increase this value(default 4MB) to boost concurrency if you have many clients to serve and you get a powerful server at the same time, and also you can decrease this value to serve only 1 or 2 clients and hope this program can run under some embeded SoC system with limited memory and only you can access. (Notice that the `-smuxbuf` value is not proprotional to concurrency, you need to test.)
|
||||
`-smuxbuf` also affects the maximum memory consumption, this parameter maintains a subtle balance between *concurrency* and *resource*, you can increase this value(default 4MB) to boost concurrency if you have many clients to serve and you get a powerful server at the same time, and also you can decrease this value to serve only 1 or 2 clients and hope this program can run under some embedded SoC system with limited memory and only you can access. (Notice that the `-smuxbuf` value is not proprotional to concurrency, you need to test.)
|
||||
|
||||
|
||||
#### Compression
|
||||
@@ -357,13 +355,11 @@ Low-level KCP configuration can be altered by using manual mode like above, make
|
||||
|
||||
### Identical Parmeters
|
||||
|
||||
The parameters below **MUST** be **IDENTICAL** on **BOTH** side:
|
||||
These parameters **MUST** be **IDENTICAL** on **BOTH** side:
|
||||
|
||||
1. -key
|
||||
1. -crypt
|
||||
1. -nocomp
|
||||
1. -datashard
|
||||
1. -parityshard
|
||||
1. -smuxver
|
||||
|
||||
### References
|
||||
|
||||
@@ -57,6 +57,12 @@ for os in ${OSES[@]}; do
|
||||
$sum kcptun-${os}-386-$VERSION.tar.gz
|
||||
done
|
||||
|
||||
#Apple M1 device
|
||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_darwin_arm64 github.com/xtaci/kcptun/server
|
||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_darwin_arm64 github.com/xtaci/kcptun/client
|
||||
tar -zcf kcptun-darwin-arm64-$VERSION.tar.gz client_darwin_arm64 server_darwin_arm64
|
||||
$sum kcptun-darwin-arm64-$VERSION.tar.gz
|
||||
|
||||
# ARM
|
||||
ARMS=(5 6 7)
|
||||
for v in ${ARMS[@]}; do
|
||||
|
||||
+41
-32
@@ -73,6 +73,11 @@ func checkError(err error) {
|
||||
}
|
||||
}
|
||||
|
||||
type timedSession struct {
|
||||
session *smux.Session
|
||||
expiryDate time.Time
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(int64(time.Now().Nanosecond()))
|
||||
if VERSION == "SELFBUILD" {
|
||||
@@ -124,7 +129,7 @@ func main() {
|
||||
cli.IntFlag{
|
||||
Name: "scavengettl",
|
||||
Value: 600,
|
||||
Usage: "set how long an expired connection can live(in sec), -1 to disable",
|
||||
Usage: "set how long an expired connection can live (in seconds)",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "mtu",
|
||||
@@ -421,20 +426,16 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
numconn := uint16(config.Conn)
|
||||
muxes := make([]struct {
|
||||
session *smux.Session
|
||||
ttl time.Time
|
||||
}, numconn)
|
||||
|
||||
for k := range muxes {
|
||||
muxes[k].session = waitConn()
|
||||
muxes[k].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
}
|
||||
|
||||
chScavenger := make(chan *smux.Session, 128)
|
||||
go scavenger(chScavenger, config.ScavengeTTL)
|
||||
// start snmp logger
|
||||
go generic.SnmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
|
||||
// start scavenger
|
||||
chScavenger := make(chan timedSession, 128)
|
||||
go scavenger(chScavenger, &config)
|
||||
|
||||
// start listener
|
||||
numconn := uint16(config.Conn)
|
||||
muxes := make([]timedSession, numconn)
|
||||
rr := uint16(0)
|
||||
for {
|
||||
p1, err := listener.AcceptTCP()
|
||||
@@ -444,10 +445,13 @@ func main() {
|
||||
idx := rr % numconn
|
||||
|
||||
// do auto expiration && reconnection
|
||||
if muxes[idx].session.IsClosed() || (config.AutoExpire > 0 && time.Now().After(muxes[idx].ttl)) {
|
||||
chScavenger <- muxes[idx].session
|
||||
if muxes[idx].session == nil || muxes[idx].session.IsClosed() ||
|
||||
(config.AutoExpire > 0 && time.Now().After(muxes[idx].expiryDate)) {
|
||||
muxes[idx].session = waitConn()
|
||||
muxes[idx].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
muxes[idx].expiryDate = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
if config.AutoExpire > 0 { // only when autoexpire set
|
||||
chScavenger <- muxes[idx]
|
||||
}
|
||||
}
|
||||
|
||||
go handleClient(muxes[idx].session, p1, config.Quiet)
|
||||
@@ -457,30 +461,35 @@ func main() {
|
||||
myApp.Run(os.Args)
|
||||
}
|
||||
|
||||
type scavengeSession struct {
|
||||
session *smux.Session
|
||||
ts time.Time
|
||||
}
|
||||
func scavenger(ch chan timedSession, config *Config) {
|
||||
// When AutoExpire is set to 0 (default), sessionList will keep empty.
|
||||
// Then this routine won't need to do anything; thus just terminate it.
|
||||
if config.AutoExpire <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
func scavenger(ch chan *smux.Session, ttl int) {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
var sessionList []scavengeSession
|
||||
var sessionList []timedSession
|
||||
for {
|
||||
select {
|
||||
case sess := <-ch:
|
||||
sessionList = append(sessionList, scavengeSession{sess, time.Now()})
|
||||
log.Println("session marked as expired", sess.RemoteAddr())
|
||||
case item := <-ch:
|
||||
sessionList = append(sessionList, timedSession{
|
||||
item.session,
|
||||
item.expiryDate.Add(time.Duration(config.ScavengeTTL) * time.Second)})
|
||||
case <-ticker.C:
|
||||
var newList []scavengeSession
|
||||
if len(sessionList) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var newList []timedSession
|
||||
for k := range sessionList {
|
||||
s := sessionList[k]
|
||||
if s.session.NumStreams() == 0 || s.session.IsClosed() {
|
||||
log.Println("session normally closed", s.session.RemoteAddr())
|
||||
s.session.Close()
|
||||
} else if ttl >= 0 && time.Since(s.ts) >= time.Duration(ttl)*time.Second {
|
||||
log.Println("session reached scavenge ttl", s.session.RemoteAddr())
|
||||
if s.session.IsClosed() {
|
||||
log.Println("scavenger: session normally closed:", s.session.LocalAddr())
|
||||
} else if time.Now().After(s.expiryDate) {
|
||||
s.session.Close()
|
||||
log.Println("scavenger: session closed due to ttl:", s.session.LocalAddr())
|
||||
} else {
|
||||
newList = append(newList, sessionList[k])
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
[unit]
|
||||
Description=kcptun
|
||||
|
||||
Wants=network.target
|
||||
|
||||
@@ -4,12 +4,16 @@ require (
|
||||
github.com/coreos/go-iptables v0.4.2 // indirect
|
||||
github.com/golang/snappy v0.0.1
|
||||
github.com/google/gopacket v1.1.17 // indirect
|
||||
github.com/klauspost/reedsolomon v1.10.0 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/urfave/cli v1.21.0
|
||||
github.com/xtaci/kcp-go/v5 v5.5.17
|
||||
github.com/xtaci/smux v1.5.14
|
||||
github.com/xtaci/kcp-go/v5 v5.6.1
|
||||
github.com/xtaci/smux v1.5.16
|
||||
github.com/xtaci/tcpraw v1.2.25
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
|
||||
)
|
||||
|
||||
go 1.14
|
||||
|
||||
@@ -1,35 +1,67 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/go-iptables v0.4.2 h1:KH0EwId05JwWIfb96gWvkiT2cbuOu8ygqUaB+yPAwIg=
|
||||
github.com/coreos/go-iptables v0.4.2/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=
|
||||
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
|
||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
||||
github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54=
|
||||
github.com/klauspost/cpuid/v2 v2.0.14 h1:QRqdp6bb9M9S5yyKeYteXKuoKE4p0tGlra81fKOpWH8=
|
||||
github.com/klauspost/cpuid/v2 v2.0.14/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo=
|
||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 h1:ULR/QWMgcgRiZLUjSSJMU+fW+RDMstRdmnDWj9Q+AsA=
|
||||
github.com/klauspost/reedsolomon v1.10.0 h1:MonMtg979rxSHjwtsla5dZLhreS0Lu42AyQ20bhjIGg=
|
||||
github.com/klauspost/reedsolomon v1.10.0/go.mod h1:qHMIzMkuZUWqIh8mS/GruPdo3u0qwX2jk/LH440ON7Y=
|
||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/templexxx/cpu v0.0.1 h1:hY4WdLOgKdc8y13EYklu9OUTXik80BkxHoWvTO6MQQY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
||||
github.com/templexxx/cpu v0.0.7 h1:pUEZn8JBy/w5yzdYWgx+0m0xL9uk6j4K91C5kOViAzo=
|
||||
github.com/templexxx/cpu v0.0.7/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
||||
github.com/templexxx/xorsimd v0.4.1 h1:iUZcywbOYDRAZUasAs2eSCUW8eobuZDy0I9FJiORkVg=
|
||||
github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
|
||||
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
|
||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE=
|
||||
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
|
||||
github.com/xtaci/kcp-go/v5 v5.5.17 h1:bkdaqtER0PMlP05BBHfu6W+71kt/NwbAk93KH7F78Ck=
|
||||
github.com/xtaci/kcp-go/v5 v5.5.17/go.mod h1:pVx3jb4LT5edTmPayc77tIU9nRsjGck8wep5ZV/RBO0=
|
||||
github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI=
|
||||
github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo=
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
||||
github.com/xtaci/smux v1.5.14 h1:1j+zJYDZRv9FHaWqCJfH5RPizIm0fSzJIFbfVn8zsfg=
|
||||
github.com/xtaci/smux v1.5.14/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
|
||||
github.com/xtaci/smux v1.5.16 h1:FBPYOkW8ZTjLKUM4LI4xnnuuDC8CQ/dB04HD519WoEk=
|
||||
github.com/xtaci/smux v1.5.16/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
|
||||
github.com/xtaci/tcpraw v1.2.25 h1:VDlqo0op17JeXBM6e2G9ocCNLOJcw9mZbobMbJjo0vk=
|
||||
github.com/xtaci/tcpraw v1.2.25/go.mod h1:dKyZ2V75s0cZ7cbgJYdxPvms7af0joIeOyx1GgJQbLk=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@@ -39,36 +71,85 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9 h1:yi1hN8dcqI9l8klZfy4B8mJvFmmAxJEePIQQFNSd7Cs=
|
||||
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123 h1:4JSJPND/+4555t1HfXYF4UEqDqiSKCgeV0+hbA8hMs4=
|
||||
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
%global debug_package %{nil}
|
||||
%global _dwz_low_mem_die_limit 0
|
||||
%global __os_install_post /usr/lib/rpm/brp-compress %{nil}
|
||||
|
||||
Name: kcptun
|
||||
Version: 20210922
|
||||
Release: 1
|
||||
Summary: A Stable & Secure Tunnel based on KCP with N:M multiplexing and FEC
|
||||
|
||||
License: MIT
|
||||
URL: https://github.com/xtaci/kcptun
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
BuildRequires: golang
|
||||
BuildRequires: glibc-static
|
||||
|
||||
%description
|
||||
A Stable & Secure Tunnel based on KCP with N:M multiplexing and FEC
|
||||
|
||||
%package server
|
||||
Summary: kcptun-server
|
||||
Requires: systemd
|
||||
|
||||
%description server
|
||||
A Stable & Secure Tunnel based on KCP with N:M multiplexing and FEC
|
||||
|
||||
%package client
|
||||
Summary: kcptun-client
|
||||
Requires: systemd
|
||||
|
||||
%description client
|
||||
A Stable & Secure Tunnel based on KCP with N:M multiplexing and FEC
|
||||
|
||||
%prep
|
||||
%autosetup
|
||||
|
||||
%build
|
||||
LDFLAGS='-s -w -linkmode=external -extldflags -static -X main.VERSION=%{version}'
|
||||
go build -ldflags "$LDFLAGS" -o %{name}-server github.com/xtaci/kcptun/server
|
||||
go build -ldflags "$LDFLAGS" -o %{name}-client github.com/xtaci/kcptun/client
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%{__mkdir} -p $RPM_BUILD_ROOT%{_bindir}
|
||||
%{__install} -p -m 755 kcptun-server $RPM_BUILD_ROOT%{_bindir}/kcptun-server
|
||||
%{__install} -p -m 755 kcptun-client $RPM_BUILD_ROOT%{_bindir}/kcptun-client
|
||||
|
||||
%{__mkdir} -p $RPM_BUILD_ROOT%{_sysconfdir}/%{name}
|
||||
%{__install} -p -m 644 examples/server.json $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/server.json
|
||||
%{__install} -p -m 644 examples/local.json $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/client.json
|
||||
|
||||
%{__mkdir} -p $RPM_BUILD_ROOT%{_unitdir}
|
||||
cat > $RPM_BUILD_ROOT%{_unitdir}/kcptun-server.service <<EOF
|
||||
[Unit]
|
||||
Description=kcptun-server
|
||||
Wants=network.target
|
||||
After=syslog.target network-online.target
|
||||
ConditionFileIsExecutable=/usr/bin/kcptun-server
|
||||
ConditionPathExists=/etc/kcptun/server.json
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=GOGC=20
|
||||
ExecStart=/usr/bin/kcptun-server -c /etc/kcptun/server.json
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
KillMode=process
|
||||
LimitNOFILE=65536
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
cat > $RPM_BUILD_ROOT%{_unitdir}/kcptun-client.service <<EOF
|
||||
[Unit]
|
||||
Description=kcptun-client
|
||||
After=syslog.target network-online.target
|
||||
ConditionFileIsExecutable=/usr/bin/kcptun-client
|
||||
ConditionPathExists=/etc/kcptun/client.json
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=GOGC=20
|
||||
ExecStart=/usr/bin/kcptun-client -c /etc/kcptun/client.json
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
KillMode=process
|
||||
LimitNOFILE=65536
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
%post server
|
||||
%systemd_post %{name}-server.service
|
||||
|
||||
%preun server
|
||||
%systemd_preun %{name}-server.service
|
||||
|
||||
%postun server
|
||||
%systemd_postun_with_restart %{name}-server.service
|
||||
|
||||
%post client
|
||||
%systemd_post %{name}-client.service
|
||||
|
||||
%preun client
|
||||
%systemd_preun %{name}-client.service
|
||||
|
||||
%postun client
|
||||
%systemd_postun_with_restart %{name}-client.service
|
||||
|
||||
%files server
|
||||
%defattr(-,root,root,-)
|
||||
%{_bindir}/kcptun-server
|
||||
%config(noreplace) %{_sysconfdir}/%{name}/server.json
|
||||
%{_unitdir}/kcptun-server.service
|
||||
%license LICENSE.md
|
||||
%doc README.md Dockerfile
|
||||
|
||||
%files client
|
||||
%defattr(-,root,root,-)
|
||||
%{_bindir}/kcptun-client
|
||||
%config(noreplace) %{_sysconfdir}/%{name}/client.json
|
||||
%{_unitdir}/kcptun-client.service
|
||||
%license LICENSE.md
|
||||
%doc README.md Dockerfile
|
||||
|
||||
%changelog
|
||||
* Thu Dec 30 2021 Purple Grape <purplegrape4@gmail.com>
|
||||
- First package for kcptun
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
language: go
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
- arm64
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
- master
|
||||
|
||||
script:
|
||||
- go vet ./...
|
||||
- go test -race ./...
|
||||
- go test -tags=noasm ./...
|
||||
|
||||
stages:
|
||||
- gofmt
|
||||
- test
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: 'master'
|
||||
fast_finish: true
|
||||
include:
|
||||
- stage: gofmt
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- diff <(gofmt -d .) <(printf "")
|
||||
- diff <(gofmt -d ./private) <(printf "")
|
||||
- go install github.com/klauspost/asmfmt/cmd/asmfmt
|
||||
- diff <(asmfmt -d .) <(printf "")
|
||||
- stage: i386
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- GOOS=linux GOARCH=386 go test .
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2015- Klaus Post & Contributors.
|
||||
Email: klauspost@gmail.com
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Klaus Post
|
||||
|
||||
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.
|
||||
|
||||
-191
@@ -1,191 +0,0 @@
|
||||
# cpuid
|
||||
Package cpuid provides information about the CPU running the current program.
|
||||
|
||||
CPU features are detected on startup, and kept for fast access through the life of the application.
|
||||
Currently x86 / x64 (AMD64/i386) and ARM (ARM64) is supported, and no external C (cgo) code is used, which should make the library very easy to use.
|
||||
|
||||
You can access the CPU information by accessing the shared CPU variable of the cpuid library.
|
||||
|
||||
Package home: https://github.com/klauspost/cpuid
|
||||
|
||||
[![GoDoc][1]][2] [![Build Status][3]][4]
|
||||
|
||||
[1]: https://godoc.org/github.com/klauspost/cpuid?status.svg
|
||||
[2]: https://godoc.org/github.com/klauspost/cpuid
|
||||
[3]: https://travis-ci.org/klauspost/cpuid.svg?branch=master
|
||||
[4]: https://travis-ci.org/klauspost/cpuid
|
||||
|
||||
# features
|
||||
|
||||
## x86 CPU Instructions
|
||||
* **CMOV** (i686 CMOV)
|
||||
* **NX** (NX (No-Execute) bit)
|
||||
* **AMD3DNOW** (AMD 3DNOW)
|
||||
* **AMD3DNOWEXT** (AMD 3DNowExt)
|
||||
* **MMX** (standard MMX)
|
||||
* **MMXEXT** (SSE integer functions or AMD MMX ext)
|
||||
* **SSE** (SSE functions)
|
||||
* **SSE2** (P4 SSE functions)
|
||||
* **SSE3** (Prescott SSE3 functions)
|
||||
* **SSSE3** (Conroe SSSE3 functions)
|
||||
* **SSE4** (Penryn SSE4.1 functions)
|
||||
* **SSE4A** (AMD Barcelona microarchitecture SSE4a instructions)
|
||||
* **SSE42** (Nehalem SSE4.2 functions)
|
||||
* **AVX** (AVX functions)
|
||||
* **AVX2** (AVX2 functions)
|
||||
* **FMA3** (Intel FMA 3)
|
||||
* **FMA4** (Bulldozer FMA4 functions)
|
||||
* **XOP** (Bulldozer XOP functions)
|
||||
* **F16C** (Half-precision floating-point conversion)
|
||||
* **BMI1** (Bit Manipulation Instruction Set 1)
|
||||
* **BMI2** (Bit Manipulation Instruction Set 2)
|
||||
* **TBM** (AMD Trailing Bit Manipulation)
|
||||
* **LZCNT** (LZCNT instruction)
|
||||
* **POPCNT** (POPCNT instruction)
|
||||
* **AESNI** (Advanced Encryption Standard New Instructions)
|
||||
* **CLMUL** (Carry-less Multiplication)
|
||||
* **HTT** (Hyperthreading (enabled))
|
||||
* **HLE** (Hardware Lock Elision)
|
||||
* **RTM** (Restricted Transactional Memory)
|
||||
* **RDRAND** (RDRAND instruction is available)
|
||||
* **RDSEED** (RDSEED instruction is available)
|
||||
* **ADX** (Intel ADX (Multi-Precision Add-Carry Instruction Extensions))
|
||||
* **SHA** (Intel SHA Extensions)
|
||||
* **AVX512F** (AVX-512 Foundation)
|
||||
* **AVX512DQ** (AVX-512 Doubleword and Quadword Instructions)
|
||||
* **AVX512IFMA** (AVX-512 Integer Fused Multiply-Add Instructions)
|
||||
* **AVX512PF** (AVX-512 Prefetch Instructions)
|
||||
* **AVX512ER** (AVX-512 Exponential and Reciprocal Instructions)
|
||||
* **AVX512CD** (AVX-512 Conflict Detection Instructions)
|
||||
* **AVX512BW** (AVX-512 Byte and Word Instructions)
|
||||
* **AVX512VL** (AVX-512 Vector Length Extensions)
|
||||
* **AVX512VBMI** (AVX-512 Vector Bit Manipulation Instructions)
|
||||
* **AVX512VBMI2** (AVX-512 Vector Bit Manipulation Instructions, Version 2)
|
||||
* **AVX512VNNI** (AVX-512 Vector Neural Network Instructions)
|
||||
* **AVX512VPOPCNTDQ** (AVX-512 Vector Population Count Doubleword and Quadword)
|
||||
* **GFNI** (Galois Field New Instructions)
|
||||
* **VAES** (Vector AES)
|
||||
* **AVX512BITALG** (AVX-512 Bit Algorithms)
|
||||
* **VPCLMULQDQ** (Carry-Less Multiplication Quadword)
|
||||
* **AVX512BF16** (AVX-512 BFLOAT16 Instructions)
|
||||
* **AVX512VP2INTERSECT** (AVX-512 Intersect for D/Q)
|
||||
* **MPX** (Intel MPX (Memory Protection Extensions))
|
||||
* **ERMS** (Enhanced REP MOVSB/STOSB)
|
||||
* **RDTSCP** (RDTSCP Instruction)
|
||||
* **CX16** (CMPXCHG16B Instruction)
|
||||
* **SGX** (Software Guard Extensions, with activation details)
|
||||
* **VMX** (Virtual Machine Extensions)
|
||||
|
||||
## Performance
|
||||
* **RDTSCP()** Returns current cycle count. Can be used for benchmarking.
|
||||
* **SSE2SLOW** (SSE2 is supported, but usually not faster)
|
||||
* **SSE3SLOW** (SSE3 is supported, but usually not faster)
|
||||
* **ATOM** (Atom processor, some SSSE3 instructions are slower)
|
||||
* **Cache line** (Probable size of a cache line).
|
||||
* **L1, L2, L3 Cache size** on newer Intel/AMD CPUs.
|
||||
|
||||
## ARM CPU features
|
||||
|
||||
# ARM FEATURE DETECTION DISABLED!
|
||||
|
||||
See [#52](https://github.com/klauspost/cpuid/issues/52).
|
||||
|
||||
Currently only `arm64` platforms are implemented.
|
||||
|
||||
* **FP** Single-precision and double-precision floating point
|
||||
* **ASIMD** Advanced SIMD
|
||||
* **EVTSTRM** Generic timer
|
||||
* **AES** AES instructions
|
||||
* **PMULL** Polynomial Multiply instructions (PMULL/PMULL2)
|
||||
* **SHA1** SHA-1 instructions (SHA1C, etc)
|
||||
* **SHA2** SHA-2 instructions (SHA256H, etc)
|
||||
* **CRC32** CRC32/CRC32C instructions
|
||||
* **ATOMICS** Large System Extensions (LSE)
|
||||
* **FPHP** Half-precision floating point
|
||||
* **ASIMDHP** Advanced SIMD half-precision floating point
|
||||
* **ARMCPUID** Some CPU ID registers readable at user-level
|
||||
* **ASIMDRDM** Rounding Double Multiply Accumulate/Subtract (SQRDMLAH/SQRDMLSH)
|
||||
* **JSCVT** Javascript-style double->int convert (FJCVTZS)
|
||||
* **FCMA** Floating point complex number addition and multiplication
|
||||
* **LRCPC** Weaker release consistency (LDAPR, etc)
|
||||
* **DCPOP** Data cache clean to Point of Persistence (DC CVAP)
|
||||
* **SHA3** SHA-3 instructions (EOR3, RAXI, XAR, BCAX)
|
||||
* **SM3** SM3 instructions
|
||||
* **SM4** SM4 instructions
|
||||
* **ASIMDDP** SIMD Dot Product
|
||||
* **SHA512** SHA512 instructions
|
||||
* **SVE** Scalable Vector Extension
|
||||
* **GPA** Generic Pointer Authentication
|
||||
|
||||
## Cpu Vendor/VM
|
||||
* **Intel**
|
||||
* **AMD**
|
||||
* **VIA**
|
||||
* **Transmeta**
|
||||
* **NSC**
|
||||
* **KVM** (Kernel-based Virtual Machine)
|
||||
* **MSVM** (Microsoft Hyper-V or Windows Virtual PC)
|
||||
* **VMware**
|
||||
* **XenHVM**
|
||||
* **Bhyve**
|
||||
* **Hygon**
|
||||
|
||||
# installing
|
||||
|
||||
```go get github.com/klauspost/cpuid```
|
||||
|
||||
# example
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/klauspost/cpuid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Print basic CPU information:
|
||||
fmt.Println("Name:", cpuid.CPU.BrandName)
|
||||
fmt.Println("PhysicalCores:", cpuid.CPU.PhysicalCores)
|
||||
fmt.Println("ThreadsPerCore:", cpuid.CPU.ThreadsPerCore)
|
||||
fmt.Println("LogicalCores:", cpuid.CPU.LogicalCores)
|
||||
fmt.Println("Family", cpuid.CPU.Family, "Model:", cpuid.CPU.Model)
|
||||
fmt.Println("Features:", cpuid.CPU.Features)
|
||||
fmt.Println("Cacheline bytes:", cpuid.CPU.CacheLine)
|
||||
fmt.Println("L1 Data Cache:", cpuid.CPU.Cache.L1D, "bytes")
|
||||
fmt.Println("L1 Instruction Cache:", cpuid.CPU.Cache.L1D, "bytes")
|
||||
fmt.Println("L2 Cache:", cpuid.CPU.Cache.L2, "bytes")
|
||||
fmt.Println("L3 Cache:", cpuid.CPU.Cache.L3, "bytes")
|
||||
|
||||
// Test if we have a specific feature:
|
||||
if cpuid.CPU.SSE() {
|
||||
fmt.Println("We have Streaming SIMD Extensions")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Sample output:
|
||||
```
|
||||
>go run main.go
|
||||
Name: Intel(R) Core(TM) i5-2540M CPU @ 2.60GHz
|
||||
PhysicalCores: 2
|
||||
ThreadsPerCore: 2
|
||||
LogicalCores: 4
|
||||
Family 6 Model: 42
|
||||
Features: CMOV,MMX,MMXEXT,SSE,SSE2,SSE3,SSSE3,SSE4.1,SSE4.2,AVX,AESNI,CLMUL
|
||||
Cacheline bytes: 64
|
||||
We have Streaming SIMD Extensions
|
||||
```
|
||||
|
||||
# private package
|
||||
|
||||
In the "private" folder you can find an autogenerated version of the library you can include in your own packages.
|
||||
|
||||
For this purpose all exports are removed, and functions and constants are lowercased.
|
||||
|
||||
This is not a recommended way of using the library, but provided for convenience, if it is difficult for you to use external packages.
|
||||
|
||||
# license
|
||||
|
||||
This code is published under an MIT license. See LICENSE file for more information.
|
||||
-1504
File diff suppressed because it is too large
Load Diff
-42
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build 386,!gccgo,!noasm,!appengine
|
||||
|
||||
// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmCpuid(SB), 7, $0
|
||||
XORL CX, CX
|
||||
MOVL op+0(FP), AX
|
||||
CPUID
|
||||
MOVL AX, eax+4(FP)
|
||||
MOVL BX, ebx+8(FP)
|
||||
MOVL CX, ecx+12(FP)
|
||||
MOVL DX, edx+16(FP)
|
||||
RET
|
||||
|
||||
// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmCpuidex(SB), 7, $0
|
||||
MOVL op+0(FP), AX
|
||||
MOVL op2+4(FP), CX
|
||||
CPUID
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL BX, ebx+12(FP)
|
||||
MOVL CX, ecx+16(FP)
|
||||
MOVL DX, edx+20(FP)
|
||||
RET
|
||||
|
||||
// func xgetbv(index uint32) (eax, edx uint32)
|
||||
TEXT ·asmXgetbv(SB), 7, $0
|
||||
MOVL index+0(FP), CX
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
|
||||
MOVL AX, eax+4(FP)
|
||||
MOVL DX, edx+8(FP)
|
||||
RET
|
||||
|
||||
// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmRdtscpAsm(SB), 7, $0
|
||||
BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
|
||||
MOVL AX, eax+0(FP)
|
||||
MOVL BX, ebx+4(FP)
|
||||
MOVL CX, ecx+8(FP)
|
||||
MOVL DX, edx+12(FP)
|
||||
RET
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build amd64,!gccgo,!noasm,!appengine
|
||||
|
||||
// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmCpuid(SB), 7, $0
|
||||
XORQ CX, CX
|
||||
MOVL op+0(FP), AX
|
||||
CPUID
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL BX, ebx+12(FP)
|
||||
MOVL CX, ecx+16(FP)
|
||||
MOVL DX, edx+20(FP)
|
||||
RET
|
||||
|
||||
// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmCpuidex(SB), 7, $0
|
||||
MOVL op+0(FP), AX
|
||||
MOVL op2+4(FP), CX
|
||||
CPUID
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL BX, ebx+12(FP)
|
||||
MOVL CX, ecx+16(FP)
|
||||
MOVL DX, edx+20(FP)
|
||||
RET
|
||||
|
||||
// func asmXgetbv(index uint32) (eax, edx uint32)
|
||||
TEXT ·asmXgetbv(SB), 7, $0
|
||||
MOVL index+0(FP), CX
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL DX, edx+12(FP)
|
||||
RET
|
||||
|
||||
// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·asmRdtscpAsm(SB), 7, $0
|
||||
BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
|
||||
MOVL AX, eax+0(FP)
|
||||
MOVL BX, ebx+4(FP)
|
||||
MOVL CX, ecx+8(FP)
|
||||
MOVL DX, edx+12(FP)
|
||||
RET
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build 386,!gccgo,!noasm amd64,!gccgo,!noasm,!appengine
|
||||
|
||||
package cpuid
|
||||
|
||||
func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
|
||||
func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
|
||||
func asmXgetbv(index uint32) (eax, edx uint32)
|
||||
func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
|
||||
|
||||
func initCPU() {
|
||||
cpuid = asmCpuid
|
||||
cpuidex = asmCpuidex
|
||||
xgetbv = asmXgetbv
|
||||
rdtscpAsm = asmRdtscpAsm
|
||||
}
|
||||
|
||||
func addInfo(c *CPUInfo) {
|
||||
c.maxFunc = maxFunctionID()
|
||||
c.maxExFunc = maxExtendedFunction()
|
||||
c.BrandName = brandName()
|
||||
c.CacheLine = cacheLine()
|
||||
c.Family, c.Model = familyModel()
|
||||
c.Features = support()
|
||||
c.SGX = hasSGX(c.Features&SGX != 0, c.Features&SGXLC != 0)
|
||||
c.ThreadsPerCore = threadsPerCore()
|
||||
c.LogicalCores = logicalCores()
|
||||
c.PhysicalCores = physicalCores()
|
||||
c.VendorID, c.VendorString = vendorID()
|
||||
c.Hz = hertz(c.BrandName)
|
||||
c.cacheSize()
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build !amd64,!386,!arm64 gccgo noasm appengine
|
||||
|
||||
package cpuid
|
||||
|
||||
func initCPU() {
|
||||
cpuid = func(uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
cpuidex = func(x, y uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
xgetbv = func(uint32) (a, b uint32) { return 0, 0 }
|
||||
rdtscpAsm = func() (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
}
|
||||
|
||||
func addInfo(info *CPUInfo) {}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
language: go
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
- s390x
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
- master
|
||||
|
||||
install:
|
||||
- go get ./...
|
||||
|
||||
script:
|
||||
- go vet ./...
|
||||
- go test -cpu=1,2 .
|
||||
- go test -tags=noasm -cpu=1,2 .
|
||||
- go build examples/simple-decoder.go
|
||||
- go build examples/simple-encoder.go
|
||||
- go build examples/stream-decoder.go
|
||||
- go build examples/stream-encoder.go
|
||||
|
||||
stages:
|
||||
- gofmt
|
||||
- test
|
||||
- deploy
|
||||
|
||||
jobs:
|
||||
allow_failures:
|
||||
- go: 'master'
|
||||
- arch: s390x
|
||||
fast_finish: true
|
||||
include:
|
||||
- stage: gofmt
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- diff <(gofmt -d .) <(printf "")
|
||||
- diff <(gofmt -d ./examples) <(printf "")
|
||||
- go install github.com/klauspost/asmfmt/cmd/asmfmt
|
||||
- diff <(asmfmt -d .) <(printf "")
|
||||
- stage: race
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- go test -cpu=1 -short -race .
|
||||
- go test -cpu=2 -short -race .
|
||||
- go test -tags=noasm -cpu=1 -short -race .
|
||||
- go test -tags=noasm -cpu=4 -short -race .
|
||||
- go test -no-avx512 -short -race .
|
||||
- go test -no-avx512 -no-avx2 -short -race .
|
||||
- go test -no-avx512 -no-avx2 -no-ssse3 -short -race .
|
||||
- stage: amd64-noasm
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- go test -no-avx512
|
||||
- go test -no-avx512 -no-avx2
|
||||
- go test -no-avx512 -no-avx2 -no-ssse3
|
||||
- stage: i386
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- GOOS=linux GOARCH=386 go test -short .
|
||||
+76
-10
@@ -1,8 +1,6 @@
|
||||
# Reed-Solomon
|
||||
[![GoDoc][1]][2] [![Build Status][3]][4]
|
||||
[](https://pkg.go.dev/github.com/klauspost/reedsolomon) [![Build Status][3]][4]
|
||||
|
||||
[1]: https://godoc.org/github.com/klauspost/reedsolomon?status.svg
|
||||
[2]: https://pkg.go.dev/github.com/klauspost/reedsolomon?tab=doc
|
||||
[3]: https://travis-ci.org/klauspost/reedsolomon.svg?branch=master
|
||||
[4]: https://travis-ci.org/klauspost/reedsolomon
|
||||
|
||||
@@ -23,7 +21,19 @@ To get the package use the standard:
|
||||
go get -u github.com/klauspost/reedsolomon
|
||||
```
|
||||
|
||||
Using Go modules recommended.
|
||||
|
||||
# Changes
|
||||
## 2021
|
||||
|
||||
* Use `GOAMD64=v4` to enable faster AVX2.
|
||||
* Add progressive shard encoding.
|
||||
* Wider AVX2 loops
|
||||
* Limit concurrency on AVX2, since we are likely memory bound.
|
||||
* Allow 0 parity shards.
|
||||
* Allow disabling inversion cache.
|
||||
* Faster AVX2 encoding.
|
||||
|
||||
|
||||
## May 2020
|
||||
|
||||
@@ -178,6 +188,17 @@ If you are only interested in the data shards (for reading purposes) you can cal
|
||||
err := enc.ReconstructData(data)
|
||||
```
|
||||
|
||||
If you don't need all data shards you can use `ReconstructSome()`:
|
||||
|
||||
```Go
|
||||
// Delete two data shards
|
||||
data[3] = nil
|
||||
data[7] = nil
|
||||
|
||||
// Reconstruct just the shard 3
|
||||
err := enc.ReconstructSome(data, []bool{false, false, false, true, false, false, false, false})
|
||||
```
|
||||
|
||||
So to sum up reconstruction:
|
||||
* The number of data/parity shards must match the numbers used for encoding.
|
||||
* The order of shards must be the same as used when encoding.
|
||||
@@ -209,6 +230,49 @@ To join a data set, use the `Join()` function, which will join the shards and wr
|
||||
err = enc.Join(io.Discard, data, len(bigfile))
|
||||
```
|
||||
|
||||
# Progressive encoding
|
||||
|
||||
It is possible to encode individual shards using EncodeIdx:
|
||||
|
||||
```Go
|
||||
// EncodeIdx will add parity for a single data shard.
|
||||
// Parity shards should start out as 0. The caller must zero them.
|
||||
// Data shards must be delivered exactly once. There is no check for this.
|
||||
// The parity shards will always be updated and the data shards will remain the same.
|
||||
EncodeIdx(dataShard []byte, idx int, parity [][]byte) error
|
||||
```
|
||||
|
||||
This allows progressively encoding the parity by sending individual data shards.
|
||||
There is no requirement on shards being delivered in order,
|
||||
but when sent in order it allows encoding shards one at the time,
|
||||
effectively allowing the operation to be streaming.
|
||||
|
||||
The result will be the same as encoding all shards at once.
|
||||
There is a minor speed penalty using this method, so send
|
||||
shards at once if they are available.
|
||||
|
||||
## Example
|
||||
|
||||
```Go
|
||||
func test() {
|
||||
// Create an encoder with 7 data and 3 parity slices.
|
||||
enc, _ := reedsolomon.New(7, 3)
|
||||
|
||||
// This will be our output parity.
|
||||
parity := make([][]byte, 3)
|
||||
for i := range parity {
|
||||
parity[i] = make([]byte, 10000)
|
||||
}
|
||||
|
||||
for i := 0; i < 7; i++ {
|
||||
// Send data shards one at the time.
|
||||
_ = enc.EncodeIdx(make([]byte, 10000), i, parity)
|
||||
}
|
||||
|
||||
// parity now contains parity, as if all data was sent in one call.
|
||||
}
|
||||
```
|
||||
|
||||
# Streaming/Merging
|
||||
|
||||
It might seem like a limitation that all data should be in memory,
|
||||
@@ -300,14 +364,16 @@ Performance depends mainly on the number of parity shards.
|
||||
In rough terms, doubling the number of parity shards will double the encoding time.
|
||||
|
||||
Here are the throughput numbers with some different selections of data and parity shards.
|
||||
For reference each shard is 1MB random data, and 2 CPU cores are used for encoding.
|
||||
For reference each shard is 1MB random data, and 16 CPU cores are used for encoding.
|
||||
|
||||
| Data | Parity | Parity | MB/s | SSSE3 MB/s | SSSE3 Speed | Rel. Speed |
|
||||
|------|--------|--------|--------|-------------|-------------|------------|
|
||||
| 5 | 2 | 40% | 576,11 | 2599,2 | 451% | 100,00% |
|
||||
| 10 | 2 | 20% | 587,73 | 3100,28 | 528% | 102,02% |
|
||||
| 10 | 4 | 40% | 298,38 | 2470,97 | 828% | 51,79% |
|
||||
| 50 | 20 | 40% | 59,81 | 713,28 | 1193% | 10,38% |
|
||||
| Data | Parity | Go MB/s | SSSE3 MB/s | AVX2 MB/s |
|
||||
|------|--------|---------|------------|-----------|
|
||||
| 5 | 2 | 14287 | 66355 | 108755 |
|
||||
| 8 | 8 | 5569 | 34298 | 70516 |
|
||||
| 10 | 4 | 6766 | 48237 | 93875 |
|
||||
| 50 | 20 | 1540 | 12130 | 22090 |
|
||||
|
||||
The throughput numbers here is the size of the encoded data and parity shards.
|
||||
|
||||
If `runtime.GOMAXPROCS()` is set to a value higher than 1,
|
||||
the encoder will use multiple goroutines to perform the calculations in `Verify`, `Encode` and `Reconstruct`.
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
os: Visual Studio 2015
|
||||
|
||||
platform: x64
|
||||
|
||||
clone_folder: c:\gopath\src\github.com\klauspost\reedsolomon
|
||||
|
||||
# environment variables
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
|
||||
install:
|
||||
- echo %PATH%
|
||||
- echo %GOPATH%
|
||||
- go version
|
||||
- go env
|
||||
- go get -d ./...
|
||||
|
||||
build_script:
|
||||
- go test -v -cpu=2 ./...
|
||||
- go test -cpu=1,2,4 -short -race ./...
|
||||
+9
-7
@@ -76,7 +76,7 @@ func galSub(a, b byte) byte {
|
||||
// Table from https://github.com/templexxx/reedsolomon
|
||||
var invTable = [256]byte{0x0, 0x1, 0x8e, 0xf4, 0x47, 0xa7, 0x7a, 0xba, 0xad, 0x9d, 0xdd, 0x98, 0x3d, 0xaa, 0x5d, 0x96, 0xd8, 0x72, 0xc0, 0x58, 0xe0, 0x3e, 0x4c, 0x66, 0x90, 0xde, 0x55, 0x80, 0xa0, 0x83, 0x4b, 0x2a, 0x6c, 0xed, 0x39, 0x51, 0x60, 0x56, 0x2c, 0x8a, 0x70, 0xd0, 0x1f, 0x4a, 0x26, 0x8b, 0x33, 0x6e, 0x48, 0x89, 0x6f, 0x2e, 0xa4, 0xc3, 0x40, 0x5e, 0x50, 0x22, 0xcf, 0xa9, 0xab, 0xc, 0x15, 0xe1, 0x36, 0x5f, 0xf8, 0xd5, 0x92, 0x4e, 0xa6, 0x4, 0x30, 0x88, 0x2b, 0x1e, 0x16, 0x67, 0x45, 0x93, 0x38, 0x23, 0x68, 0x8c, 0x81, 0x1a, 0x25, 0x61, 0x13, 0xc1, 0xcb, 0x63, 0x97, 0xe, 0x37, 0x41, 0x24, 0x57, 0xca, 0x5b, 0xb9, 0xc4, 0x17, 0x4d, 0x52, 0x8d, 0xef, 0xb3, 0x20, 0xec, 0x2f, 0x32, 0x28, 0xd1, 0x11, 0xd9, 0xe9, 0xfb, 0xda, 0x79, 0xdb, 0x77, 0x6, 0xbb, 0x84, 0xcd, 0xfe, 0xfc, 0x1b, 0x54, 0xa1, 0x1d, 0x7c, 0xcc, 0xe4, 0xb0, 0x49, 0x31, 0x27, 0x2d, 0x53, 0x69, 0x2, 0xf5, 0x18, 0xdf, 0x44, 0x4f, 0x9b, 0xbc, 0xf, 0x5c, 0xb, 0xdc, 0xbd, 0x94, 0xac, 0x9, 0xc7, 0xa2, 0x1c, 0x82, 0x9f, 0xc6, 0x34, 0xc2, 0x46, 0x5, 0xce, 0x3b, 0xd, 0x3c, 0x9c, 0x8, 0xbe, 0xb7, 0x87, 0xe5, 0xee, 0x6b, 0xeb, 0xf2, 0xbf, 0xaf, 0xc5, 0x64, 0x7, 0x7b, 0x95, 0x9a, 0xae, 0xb6, 0x12, 0x59, 0xa5, 0x35, 0x65, 0xb8, 0xa3, 0x9e, 0xd2, 0xf7, 0x62, 0x5a, 0x85, 0x7d, 0xa8, 0x3a, 0x29, 0x71, 0xc8, 0xf6, 0xf9, 0x43, 0xd7, 0xd6, 0x10, 0x73, 0x76, 0x78, 0x99, 0xa, 0x19, 0x91, 0x14, 0x3f, 0xe6, 0xf0, 0x86, 0xb1, 0xe2, 0xf1, 0xfa, 0x74, 0xf3, 0xb4, 0x6d, 0x21, 0xb2, 0x6a, 0xe3, 0xe7, 0xb5, 0xea, 0x3, 0x8f, 0xd3, 0xc9, 0x42, 0xd4, 0xe8, 0x75, 0x7f, 0xff, 0x7e, 0xfd}
|
||||
|
||||
var mulTable = [256][256]uint8{[256]uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
var mulTable = [256][256]uint8{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff},
|
||||
{0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0xd, 0xf, 0x9, 0xb, 0x5, 0x7, 0x1, 0x3, 0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23, 0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43, 0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63, 0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83, 0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3, 0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3, 0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3},
|
||||
{0x0, 0x3, 0x6, 0x5, 0xc, 0xf, 0xa, 0x9, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9d, 0x9e, 0x9b, 0x98, 0x91, 0x92, 0x97, 0x94, 0x85, 0x86, 0x83, 0x80, 0x89, 0x8a, 0x8f, 0x8c, 0xad, 0xae, 0xab, 0xa8, 0xa1, 0xa2, 0xa7, 0xa4, 0xb5, 0xb6, 0xb3, 0xb0, 0xb9, 0xba, 0xbf, 0xbc, 0xfd, 0xfe, 0xfb, 0xf8, 0xf1, 0xf2, 0xf7, 0xf4, 0xe5, 0xe6, 0xe3, 0xe0, 0xe9, 0xea, 0xef, 0xec, 0xcd, 0xce, 0xcb, 0xc8, 0xc1, 0xc2, 0xc7, 0xc4, 0xd5, 0xd6, 0xd3, 0xd0, 0xd9, 0xda, 0xdf, 0xdc, 0x5d, 0x5e, 0x5b, 0x58, 0x51, 0x52, 0x57, 0x54, 0x45, 0x46, 0x43, 0x40, 0x49, 0x4a, 0x4f, 0x4c, 0x6d, 0x6e, 0x6b, 0x68, 0x61, 0x62, 0x67, 0x64, 0x75, 0x76, 0x73, 0x70, 0x79, 0x7a, 0x7f, 0x7c, 0x3d, 0x3e, 0x3b, 0x38, 0x31, 0x32, 0x37, 0x34, 0x25, 0x26, 0x23, 0x20, 0x29, 0x2a, 0x2f, 0x2c, 0xd, 0xe, 0xb, 0x8, 0x1, 0x2, 0x7, 0x4, 0x15, 0x16, 0x13, 0x10, 0x19, 0x1a, 0x1f, 0x1c},
|
||||
@@ -901,7 +901,7 @@ func galExp(a byte, n int) byte {
|
||||
return expTable[logResult]
|
||||
}
|
||||
|
||||
func genAvx2Matrix(matrixRows [][]byte, inputs, outputs int, dst []byte) []byte {
|
||||
func genAvx2Matrix(matrixRows [][]byte, inputs, inIdx, outputs int, dst []byte) []byte {
|
||||
if !avx2CodeGen {
|
||||
panic("codegen not enabled")
|
||||
}
|
||||
@@ -915,14 +915,16 @@ func genAvx2Matrix(matrixRows [][]byte, inputs, outputs int, dst []byte) []byte
|
||||
dst = dst[:wantBytes]
|
||||
}
|
||||
for i, row := range matrixRows[:outputs] {
|
||||
for j, idx := range row[:inputs] {
|
||||
for j, idx := range row[inIdx : inIdx+inputs] {
|
||||
dstIdx := (j*outputs + i) * 64
|
||||
dstPart := dst[dstIdx:]
|
||||
dstPart = dstPart[:64]
|
||||
lo := mulTableLow[idx][:]
|
||||
hi := mulTableHigh[idx][:]
|
||||
copy(dst[dstIdx:], lo)
|
||||
copy(dst[dstIdx+16:], lo)
|
||||
copy(dst[dstIdx+32:], hi)
|
||||
copy(dst[dstIdx+48:], hi)
|
||||
copy(dstPart[:16], lo)
|
||||
copy(dstPart[16:32], lo)
|
||||
copy(dstPart[32:48], hi)
|
||||
copy(dstPart[48:64], hi)
|
||||
}
|
||||
}
|
||||
return dst
|
||||
|
||||
+9
-8
@@ -1,6 +1,5 @@
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
//go:build !noasm && !appengine && !gccgo
|
||||
// +build !noasm,!appengine,!gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2019, Minio, Inc.
|
||||
@@ -105,7 +104,7 @@ func setupMatrix84(matrixRows [][]byte, inputOffset, outputOffset int, matrix *[
|
||||
// Invoke AVX512 routine for single output row in parallel
|
||||
func galMulAVX512Parallel81(in, out [][]byte, matrixRows [][]byte, inputOffset, outputOffset, start, stop int, matrix81 *[matrixSize81]byte) {
|
||||
done := stop - start
|
||||
if done <= 0 {
|
||||
if done <= 0 || len(in) == 0 || len(out) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -140,7 +139,7 @@ func galMulAVX512Parallel81(in, out [][]byte, matrixRows [][]byte, inputOffset,
|
||||
// Invoke AVX512 routine for 2 output rows in parallel
|
||||
func galMulAVX512Parallel82(in, out [][]byte, matrixRows [][]byte, inputOffset, outputOffset, start, stop int, matrix82 *[matrixSize82]byte) {
|
||||
done := stop - start
|
||||
if done <= 0 {
|
||||
if done <= 0 || len(in) == 0 || len(out) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -175,7 +174,7 @@ func galMulAVX512Parallel82(in, out [][]byte, matrixRows [][]byte, inputOffset,
|
||||
// Invoke AVX512 routine for 4 output rows in parallel
|
||||
func galMulAVX512Parallel84(in, out [][]byte, matrixRows [][]byte, inputOffset, outputOffset, start, stop int, matrix84 *[matrixSize84]byte) {
|
||||
done := stop - start
|
||||
if done <= 0 {
|
||||
if done <= 0 || len(in) == 0 || len(out) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -226,8 +225,9 @@ func galMulAVX512LastInput(inputOffset int, inputEnd int, outputOffset int, outp
|
||||
|
||||
// Perform the same as codeSomeShards, but taking advantage of
|
||||
// AVX512 parallelism for up to 4x faster execution as compared to AVX2
|
||||
func (r *reedSolomon) codeSomeShardsAvx512(matrixRows, inputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
func (r *reedSolomon) codeSomeShardsAvx512(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
// Process using no goroutines
|
||||
outputCount := len(outputs)
|
||||
start, end := 0, r.o.perRound
|
||||
if end > byteCount {
|
||||
end = byteCount
|
||||
@@ -273,7 +273,8 @@ func (r *reedSolomon) codeSomeShardsAvx512(matrixRows, inputs, outputs [][]byte,
|
||||
|
||||
// Perform the same as codeSomeShards, but taking advantage of
|
||||
// AVX512 parallelism for up to 4x faster execution as compared to AVX2
|
||||
func (r *reedSolomon) codeSomeShardsAvx512P(matrixRows, inputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
func (r *reedSolomon) codeSomeShardsAvx512P(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
outputCount := len(outputs)
|
||||
var wg sync.WaitGroup
|
||||
do := byteCount / r.o.maxGoroutines
|
||||
if do < r.o.minSplitSize {
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
//+build !noasm !appengine !gccgo
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2019, Minio, Inc.
|
||||
|
||||
+6
-4
@@ -1,6 +1,5 @@
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
//go:build !noasm && !appengine && !gccgo
|
||||
// +build !noasm,!appengine,!gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
|
||||
@@ -108,6 +107,9 @@ func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
in = in[done:]
|
||||
out = out[done:]
|
||||
}
|
||||
if len(in) == 0 {
|
||||
return
|
||||
}
|
||||
out = out[:len(in)]
|
||||
mt := mulTable[c][:256]
|
||||
for i := range in {
|
||||
@@ -115,7 +117,7 @@ func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
}
|
||||
}
|
||||
|
||||
// slice galois add
|
||||
// simple slice xor
|
||||
func sliceXor(in, out []byte, o *options) {
|
||||
if o.useSSE2 {
|
||||
if len(in) >= bigSwitchover {
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
//+build !noasm !appengine !gccgo
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
//go:build !noasm && !appengine && !gccgo
|
||||
// +build !noasm,!appengine,!gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2017, Minio, Inc.
|
||||
@@ -52,7 +51,7 @@ func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
}
|
||||
}
|
||||
|
||||
// slice galois add
|
||||
// simple slice xor
|
||||
func sliceXor(in, out []byte, o *options) {
|
||||
|
||||
galXorNEON(in, out)
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
//+build !noasm !appengine !gccgo
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2017, Minio, Inc.
|
||||
|
||||
+1178
File diff suppressed because it is too large
Load Diff
+63422
File diff suppressed because it is too large
Load Diff
+18
@@ -0,0 +1,18 @@
|
||||
//go:build !amd64 || noasm || appengine || gccgo || nogen
|
||||
// +build !amd64 noasm appengine gccgo nogen
|
||||
|
||||
package reedsolomon
|
||||
|
||||
const maxAvx2Inputs = 1
|
||||
const maxAvx2Outputs = 1
|
||||
const minAvx2Size = 1
|
||||
const avxSizeMask = 0
|
||||
const avx2CodeGen = false
|
||||
|
||||
func galMulSlicesAvx2(matrix []byte, in, out [][]byte, start, stop int) int {
|
||||
panic("avx2 codegen not available")
|
||||
}
|
||||
|
||||
func galMulSlicesAvx2Xor(matrix []byte, in, out [][]byte, start, stop int) int {
|
||||
panic("avx2 codegen not available")
|
||||
}
|
||||
+694
@@ -0,0 +1,694 @@
|
||||
// Code generated by command: go generate gen.go. DO NOT EDIT.
|
||||
|
||||
//go:build !appengine && !noasm && gc && !nogen
|
||||
// +build !appengine,!noasm,gc,!nogen
|
||||
|
||||
package reedsolomon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
avx2CodeGen = true
|
||||
maxAvx2Inputs = 10
|
||||
maxAvx2Outputs = 10
|
||||
minAvx2Size = 64
|
||||
avxSizeMask = maxInt - (minAvx2Size - 1)
|
||||
)
|
||||
|
||||
func galMulSlicesAvx2(matrix []byte, in, out [][]byte, start, stop int) int {
|
||||
n := (stop - start) & avxSizeMask
|
||||
|
||||
switch len(in) {
|
||||
case 1:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_1x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_1x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_1x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_1x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_1x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_1x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_1x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_1x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_1x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_1x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 2:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_2x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_2x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_2x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_2x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_2x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_2x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_2x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_2x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_2x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_2x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 3:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_3x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_3x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_3x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_3x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_3x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_3x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_3x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_3x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_3x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_3x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 4:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_4x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_4x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_4x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_4x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_4x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_4x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_4x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_4x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_4x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_4x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 5:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_5x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_5x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_5x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_5x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_5x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_5x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_5x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_5x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_5x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_5x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 6:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_6x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_6x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_6x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_6x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_6x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_6x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_6x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_6x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_6x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_6x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 7:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_7x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_7x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_7x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_7x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_7x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_7x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_7x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_7x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_7x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_7x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 8:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_8x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_8x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_8x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_8x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_8x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_8x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_8x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_8x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_8x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_8x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 9:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_9x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_9x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_9x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_9x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_9x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_9x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_9x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_9x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_9x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_9x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 10:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_10x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_10x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_10x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_10x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_10x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_10x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_10x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_10x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_10x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_10x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("unhandled size: %dx%d", len(in), len(out)))
|
||||
}
|
||||
|
||||
func galMulSlicesAvx2Xor(matrix []byte, in, out [][]byte, start, stop int) int {
|
||||
n := (stop - start) & avxSizeMask
|
||||
|
||||
switch len(in) {
|
||||
case 1:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_1x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_1x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_1x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_1x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_1x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_1x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_1x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_1x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_1x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_1x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 2:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_2x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_2x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_2x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_2x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_2x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_2x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_2x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_2x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_2x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_2x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 3:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_3x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_3x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_3x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_3x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_3x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_3x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_3x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_3x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_3x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_3x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 4:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_4x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_4x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_4x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_4x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_4x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_4x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_4x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_4x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_4x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_4x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 5:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_5x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_5x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_5x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_5x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_5x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_5x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_5x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_5x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_5x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_5x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 6:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_6x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_6x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_6x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_6x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_6x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_6x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_6x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_6x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_6x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_6x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 7:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_7x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_7x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_7x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_7x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_7x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_7x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_7x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_7x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_7x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_7x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 8:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_8x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_8x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_8x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_8x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_8x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_8x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_8x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_8x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_8x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_8x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 9:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_9x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_9x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_9x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_9x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_9x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_9x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_9x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_9x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_9x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_9x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 10:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_10x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_10x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_10x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_10x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_10x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_10x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_10x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_10x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_10x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_10x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("unhandled size: %dx%d", len(in), len(out)))
|
||||
}
|
||||
+22
-8
@@ -1,11 +1,14 @@
|
||||
//+build !amd64 noasm appengine gccgo
|
||||
//+build !arm64 noasm appengine gccgo
|
||||
//+build !ppc64le noasm appengine gccgo
|
||||
//go:build (!amd64 || noasm || appengine || gccgo) && (!arm64 || noasm || appengine || gccgo) && (!ppc64le || noasm || appengine || gccgo)
|
||||
// +build !amd64 noasm appengine gccgo
|
||||
// +build !arm64 noasm appengine gccgo
|
||||
// +build !ppc64le noasm appengine gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
|
||||
package reedsolomon
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
func galMulSlice(c byte, in, out []byte, o *options) {
|
||||
out = out[:len(in)]
|
||||
if c == 1 {
|
||||
@@ -21,9 +24,7 @@ func galMulSlice(c byte, in, out []byte, o *options) {
|
||||
func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
out = out[:len(in)]
|
||||
if c == 1 {
|
||||
for n, input := range in {
|
||||
out[n] ^= input
|
||||
}
|
||||
sliceXor(in, out, o)
|
||||
return
|
||||
}
|
||||
mt := mulTable[c][:256]
|
||||
@@ -32,8 +33,21 @@ func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
}
|
||||
}
|
||||
|
||||
// slice galois add
|
||||
func sliceXor(in, out []byte, o *options) {
|
||||
// simple slice xor
|
||||
func sliceXor(in, out []byte, _ *options) {
|
||||
for len(out) >= 32 {
|
||||
inS := in[:32]
|
||||
v0 := binary.LittleEndian.Uint64(out[:]) ^ binary.LittleEndian.Uint64(inS[:])
|
||||
v1 := binary.LittleEndian.Uint64(out[8:]) ^ binary.LittleEndian.Uint64(inS[8:])
|
||||
v2 := binary.LittleEndian.Uint64(out[16:]) ^ binary.LittleEndian.Uint64(inS[16:])
|
||||
v3 := binary.LittleEndian.Uint64(out[24:]) ^ binary.LittleEndian.Uint64(inS[24:])
|
||||
binary.LittleEndian.PutUint64(out[:], v0)
|
||||
binary.LittleEndian.PutUint64(out[8:], v1)
|
||||
binary.LittleEndian.PutUint64(out[16:], v2)
|
||||
binary.LittleEndian.PutUint64(out[24:], v3)
|
||||
out = out[32:]
|
||||
in = in[32:]
|
||||
}
|
||||
for n, input := range in {
|
||||
out[n] ^= input
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//go:build !amd64 || noasm || appengine || gccgo
|
||||
// +build !amd64 noasm appengine gccgo
|
||||
|
||||
// Copyright 2020, Klaus Post, see LICENSE for details.
|
||||
|
||||
package reedsolomon
|
||||
|
||||
func (r *reedSolomon) codeSomeShardsAvx512(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
panic("codeSomeShardsAvx512 should not be called if built without asm")
|
||||
}
|
||||
|
||||
func (r *reedSolomon) codeSomeShardsAvx512P(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
panic("codeSomeShardsAvx512P should not be called if built without asm")
|
||||
}
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
//go:build !noasm && !appengine && !gccgo
|
||||
// +build !noasm,!appengine,!gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2018, Minio, Inc.
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
//+build !noasm !appengine !gccgo
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2018, Minio, Inc.
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
module github.com/klauspost/reedsolomon
|
||||
|
||||
go 1.15
|
||||
|
||||
require github.com/klauspost/cpuid/v2 v2.0.14
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
github.com/klauspost/cpuid/v2 v2.0.14 h1:QRqdp6bb9M9S5yyKeYteXKuoKE4p0tGlra81fKOpWH8=
|
||||
github.com/klauspost/cpuid/v2 v2.0.14/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
+17
-13
@@ -14,7 +14,7 @@ import (
|
||||
// The tree uses a Reader-Writer mutex to make it thread-safe
|
||||
// when accessing cached matrices and inserting new ones.
|
||||
type inversionTree struct {
|
||||
mutex *sync.RWMutex
|
||||
mutex sync.RWMutex
|
||||
root inversionNode
|
||||
}
|
||||
|
||||
@@ -26,21 +26,22 @@ type inversionNode struct {
|
||||
// newInversionTree initializes a tree for storing inverted matrices.
|
||||
// Note that the root node is the identity matrix as it implies
|
||||
// there were no errors with the original data.
|
||||
func newInversionTree(dataShards, parityShards int) inversionTree {
|
||||
func newInversionTree(dataShards, parityShards int) *inversionTree {
|
||||
identity, _ := identityMatrix(dataShards)
|
||||
root := inversionNode{
|
||||
matrix: identity,
|
||||
children: make([]*inversionNode, dataShards+parityShards),
|
||||
}
|
||||
return inversionTree{
|
||||
mutex: &sync.RWMutex{},
|
||||
root: root,
|
||||
return &inversionTree{
|
||||
root: inversionNode{
|
||||
matrix: identity,
|
||||
children: make([]*inversionNode, dataShards+parityShards),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetInvertedMatrix returns the cached inverted matrix or nil if it
|
||||
// is not found in the tree keyed on the indices of invalid rows.
|
||||
func (t inversionTree) GetInvertedMatrix(invalidIndices []int) matrix {
|
||||
func (t *inversionTree) GetInvertedMatrix(invalidIndices []int) matrix {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
// Lock the tree for reading before accessing the tree.
|
||||
t.mutex.RLock()
|
||||
defer t.mutex.RUnlock()
|
||||
@@ -63,7 +64,10 @@ var errAlreadySet = errors.New("the root node identity matrix is already set")
|
||||
// keyed by the indices of invalid rows. The total number of shards
|
||||
// is required for creating the proper length lists of child nodes for
|
||||
// each node.
|
||||
func (t inversionTree) InsertInvertedMatrix(invalidIndices []int, matrix matrix, shards int) error {
|
||||
func (t *inversionTree) InsertInvertedMatrix(invalidIndices []int, matrix matrix, shards int) error {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
// If no invalid indices were given then we are done because the
|
||||
// root node is already set with the identity matrix.
|
||||
if len(invalidIndices) == 0 {
|
||||
@@ -86,7 +90,7 @@ func (t inversionTree) InsertInvertedMatrix(invalidIndices []int, matrix matrix,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n inversionNode) getInvertedMatrix(invalidIndices []int, parent int) matrix {
|
||||
func (n *inversionNode) getInvertedMatrix(invalidIndices []int, parent int) matrix {
|
||||
// Get the child node to search next from the list of children. The
|
||||
// list of children starts relative to the parent index passed in
|
||||
// because the indices of invalid rows is sorted (by default). As we
|
||||
@@ -117,7 +121,7 @@ func (n inversionNode) getInvertedMatrix(invalidIndices []int, parent int) matri
|
||||
return node.matrix
|
||||
}
|
||||
|
||||
func (n inversionNode) insertInvertedMatrix(invalidIndices []int, matrix matrix, shards, parent int) {
|
||||
func (n *inversionNode) insertInvertedMatrix(invalidIndices []int, matrix matrix, shards, parent int) {
|
||||
// As above, get the child node to search next from the list of children.
|
||||
// The list of children starts relative to the parent index passed in
|
||||
// because the indices of invalid rows is sorted (by default). As we
|
||||
|
||||
+4
-1
@@ -218,7 +218,10 @@ func (m matrix) gaussianElimination() error {
|
||||
if m[r][r] == 0 {
|
||||
for rowBelow := r + 1; rowBelow < rows; rowBelow++ {
|
||||
if m[rowBelow][r] != 0 {
|
||||
m.SwapRows(r, rowBelow)
|
||||
err := m.SwapRows(r, rowBelow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
+44
-12
@@ -3,7 +3,7 @@ package reedsolomon
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/klauspost/cpuid"
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
// Option allows to override processing parameters.
|
||||
@@ -19,6 +19,8 @@ type options struct {
|
||||
usePAR1Matrix bool
|
||||
useCauchy bool
|
||||
fastOneParity bool
|
||||
inversionCache bool
|
||||
customMatrix [][]byte
|
||||
|
||||
// stream options
|
||||
concReads bool
|
||||
@@ -27,15 +29,16 @@ type options struct {
|
||||
}
|
||||
|
||||
var defaultOptions = options{
|
||||
maxGoroutines: 384,
|
||||
minSplitSize: -1,
|
||||
fastOneParity: false,
|
||||
maxGoroutines: 384,
|
||||
minSplitSize: -1,
|
||||
fastOneParity: false,
|
||||
inversionCache: true,
|
||||
|
||||
// Detect CPU capabilities.
|
||||
useSSSE3: cpuid.CPU.SSSE3(),
|
||||
useSSE2: cpuid.CPU.SSE2(),
|
||||
useAVX2: cpuid.CPU.AVX2(),
|
||||
useAVX512: cpuid.CPU.AVX512F() && cpuid.CPU.AVX512BW(),
|
||||
useSSSE3: cpuid.CPU.Supports(cpuid.SSSE3),
|
||||
useSSE2: cpuid.CPU.Supports(cpuid.SSE2),
|
||||
useAVX2: cpuid.CPU.Supports(cpuid.AVX2),
|
||||
useAVX512: cpuid.CPU.Supports(cpuid.AVX512F, cpuid.AVX512BW),
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -109,6 +112,15 @@ func WithConcurrentStreamWrites(enabled bool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithInversionCache allows to control the inversion cache.
|
||||
// This will cache reconstruction matrices so they can be reused.
|
||||
// Enabled by default.
|
||||
func WithInversionCache(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.inversionCache = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// WithStreamBlockSize allows to set a custom block size per round of reads/writes.
|
||||
// If not set, any shard size set with WithAutoGoroutines will be used.
|
||||
// If WithAutoGoroutines is also unset, 4MB will be used.
|
||||
@@ -119,25 +131,33 @@ func WithStreamBlockSize(n int) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func withSSSE3(enabled bool) Option {
|
||||
// WithSSSE3 allows to enable/disable SSSE3 instructions.
|
||||
// If not set, SSSE3 will be turned on or off automatically based on CPU ID information.
|
||||
func WithSSSE3(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.useSSSE3 = enabled
|
||||
}
|
||||
}
|
||||
|
||||
func withAVX2(enabled bool) Option {
|
||||
// WithAVX2 allows to enable/disable AVX2 instructions.
|
||||
// If not set, AVX2 will be turned on or off automatically based on CPU ID information.
|
||||
func WithAVX2(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.useAVX2 = enabled
|
||||
}
|
||||
}
|
||||
|
||||
func withSSE2(enabled bool) Option {
|
||||
// WithSSE2 allows to enable/disable SSE2 instructions.
|
||||
// If not set, SSE2 will be turned on or off automatically based on CPU ID information.
|
||||
func WithSSE2(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.useSSE2 = enabled
|
||||
}
|
||||
}
|
||||
|
||||
func withAVX512(enabled bool) Option {
|
||||
// WithAVX512 allows to enable/disable AVX512 instructions.
|
||||
// If not set, AVX512 will be turned on or off automatically based on CPU ID information.
|
||||
func WithAVX512(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.useAVX512 = enabled
|
||||
}
|
||||
@@ -173,3 +193,15 @@ func WithFastOneParityMatrix() Option {
|
||||
o.fastOneParity = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithCustomMatrix causes the encoder to use the manually specified matrix.
|
||||
// customMatrix represents only the parity chunks.
|
||||
// customMatrix must have at least ParityShards rows and DataShards columns.
|
||||
// It can be used for interoperability with libraries which generate
|
||||
// the matrix differently or to implement more complex coding schemes like LRC
|
||||
// (locally reconstructible codes).
|
||||
func WithCustomMatrix(customMatrix [][]byte) Option {
|
||||
return func(o *options) {
|
||||
o.customMatrix = customMatrix
|
||||
}
|
||||
}
|
||||
|
||||
+436
-126
@@ -18,7 +18,7 @@ import (
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/klauspost/cpuid"
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
// Encoder is an interface to encode Reed-Salomon parity sets for your data.
|
||||
@@ -32,6 +32,12 @@ type Encoder interface {
|
||||
// data shards while this is running.
|
||||
Encode(shards [][]byte) error
|
||||
|
||||
// EncodeIdx will add parity for a single data shard.
|
||||
// Parity shards should start out as 0. The caller must zero them.
|
||||
// Data shards must be delivered exactly once. There is no check for this.
|
||||
// The parity shards will always be updated and the data shards will remain the same.
|
||||
EncodeIdx(dataShard []byte, idx int, parity [][]byte) error
|
||||
|
||||
// Verify returns true if the parity shards contain correct data.
|
||||
// The data is the same format as Encode. No data is modified, so
|
||||
// you are allowed to read from data while this is running.
|
||||
@@ -71,6 +77,24 @@ type Encoder interface {
|
||||
// calling the Verify function is likely to fail.
|
||||
ReconstructData(shards [][]byte) error
|
||||
|
||||
// ReconstructSome will recreate only requested data shards, if possible.
|
||||
//
|
||||
// Given a list of shards, some of which contain data, fills in the
|
||||
// data shards indicated by true values in the "required" parameter.
|
||||
// The length of "required" array must be equal to DataShards.
|
||||
//
|
||||
// The length of "shards" array must be equal to Shards.
|
||||
// You indicate that a shard is missing by setting it to nil or zero-length.
|
||||
// If a shard is zero-length but has sufficient capacity, that memory will
|
||||
// be used, otherwise a new []byte will be allocated.
|
||||
//
|
||||
// If there are too few shards to reconstruct the missing
|
||||
// ones, ErrTooFewShards will be returned.
|
||||
//
|
||||
// As the reconstructed shard set may contain missing parity shards,
|
||||
// calling the Verify function is likely to fail.
|
||||
ReconstructSome(shards [][]byte, required []bool) error
|
||||
|
||||
// Update parity is use for change a few data shards and update it's parity.
|
||||
// Input 'newDatashards' containing data shards changed.
|
||||
// Input 'shards' containing old data shards (if data shard not changed, it can be nil) and old parity shards.
|
||||
@@ -102,6 +126,15 @@ type Encoder interface {
|
||||
Join(dst io.Writer, shards [][]byte, outSize int) error
|
||||
}
|
||||
|
||||
const (
|
||||
avx2CodeGenMinSize = 64
|
||||
avx2CodeGenMinShards = 3
|
||||
avx2CodeGenMaxGoroutines = 8
|
||||
|
||||
intSize = 32 << (^uint(0) >> 63) // 32 or 64
|
||||
maxInt = 1<<(intSize-1) - 1
|
||||
)
|
||||
|
||||
// reedSolomon contains a matrix for a specific
|
||||
// distribution of datashards and parity shards.
|
||||
// Construct if using New()
|
||||
@@ -110,15 +143,16 @@ type reedSolomon struct {
|
||||
ParityShards int // Number of parity shards, should not be modified.
|
||||
Shards int // Total number of shards. Calculated, and should not be modified.
|
||||
m matrix
|
||||
tree inversionTree
|
||||
tree *inversionTree
|
||||
parity [][]byte
|
||||
o options
|
||||
mPool sync.Pool
|
||||
}
|
||||
|
||||
// ErrInvShardNum will be returned by New, if you attempt to create
|
||||
// an Encoder where either data or parity shards is zero or less.
|
||||
var ErrInvShardNum = errors.New("cannot create Encoder with zero or less data/parity shards")
|
||||
// an Encoder with less than one data shard or less than zero parity
|
||||
// shards.
|
||||
var ErrInvShardNum = errors.New("cannot create Encoder with less than one data shard or less than zero parity shards")
|
||||
|
||||
// ErrMaxShardNum will be returned by New, if you attempt to create an
|
||||
// Encoder where data and parity shards are bigger than the order of
|
||||
@@ -249,7 +283,7 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
for _, opt := range opts {
|
||||
opt(&r.o)
|
||||
}
|
||||
if dataShards <= 0 || parityShards <= 0 {
|
||||
if dataShards <= 0 || parityShards < 0 {
|
||||
return nil, ErrInvShardNum
|
||||
}
|
||||
|
||||
@@ -257,8 +291,28 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
return nil, ErrMaxShardNum
|
||||
}
|
||||
|
||||
if parityShards == 0 {
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
switch {
|
||||
case r.o.customMatrix != nil:
|
||||
if len(r.o.customMatrix) < parityShards {
|
||||
return nil, errors.New("coding matrix must contain at least parityShards rows")
|
||||
}
|
||||
r.m = make([][]byte, r.Shards)
|
||||
for i := 0; i < dataShards; i++ {
|
||||
r.m[i] = make([]byte, dataShards)
|
||||
r.m[i][i] = 1
|
||||
}
|
||||
for k, row := range r.o.customMatrix {
|
||||
if len(row) < dataShards {
|
||||
return nil, errors.New("coding matrix must contain at least dataShards columns")
|
||||
}
|
||||
r.m[dataShards+k] = make([]byte, dataShards)
|
||||
copy(r.m[dataShards+k], row)
|
||||
}
|
||||
case r.o.fastOneParity && parityShards == 1:
|
||||
r.m, err = buildXorMatrix(dataShards, r.Shards)
|
||||
case r.o.useCauchy:
|
||||
@@ -274,6 +328,24 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
|
||||
// Calculate what we want per round
|
||||
r.o.perRound = cpuid.CPU.Cache.L2
|
||||
|
||||
divide := parityShards + 1
|
||||
if avx2CodeGen && r.o.useAVX2 && (dataShards > maxAvx2Inputs || parityShards > maxAvx2Outputs) {
|
||||
// Base on L1 cache if we have many inputs.
|
||||
r.o.perRound = cpuid.CPU.Cache.L1D
|
||||
divide = 0
|
||||
if dataShards > maxAvx2Inputs {
|
||||
divide += maxAvx2Inputs
|
||||
} else {
|
||||
divide += dataShards
|
||||
}
|
||||
if parityShards > maxAvx2Inputs {
|
||||
divide += maxAvx2Outputs
|
||||
} else {
|
||||
divide += parityShards
|
||||
}
|
||||
}
|
||||
|
||||
if r.o.perRound <= 0 {
|
||||
// Set to 128K if undetectable.
|
||||
r.o.perRound = 128 << 10
|
||||
@@ -283,8 +355,9 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
// If multiple threads per core, make sure they don't contend for cache.
|
||||
r.o.perRound /= cpuid.CPU.ThreadsPerCore
|
||||
}
|
||||
|
||||
// 1 input + parity must fit in cache, and we add one more to be safer.
|
||||
r.o.perRound = r.o.perRound / (1 + parityShards)
|
||||
r.o.perRound = r.o.perRound / divide
|
||||
// Align to 64 bytes.
|
||||
r.o.perRound = ((r.o.perRound + 63) / 64) * 64
|
||||
|
||||
@@ -302,10 +375,6 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if r.o.perRound < r.o.minSplitSize {
|
||||
r.o.perRound = r.o.minSplitSize
|
||||
}
|
||||
|
||||
if r.o.shardSize > 0 {
|
||||
p := runtime.GOMAXPROCS(0)
|
||||
if p == 1 || r.o.shardSize <= r.o.minSplitSize*2 {
|
||||
@@ -328,12 +397,20 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Generated AVX2 does not need data to stay in L1 cache between runs.
|
||||
// We will be purely limited by RAM speed.
|
||||
if r.canAVX2C(avx2CodeGenMinSize, maxAvx2Inputs, maxAvx2Outputs) && r.o.maxGoroutines > avx2CodeGenMaxGoroutines {
|
||||
r.o.maxGoroutines = avx2CodeGenMaxGoroutines
|
||||
}
|
||||
|
||||
// Inverted matrices are cached in a tree keyed by the indices
|
||||
// of the invalid rows of the data to reconstruct.
|
||||
// The inversion root node will have the identity matrix as
|
||||
// its inversion matrix because it implies there are no errors
|
||||
// with the original data.
|
||||
r.tree = newInversionTree(dataShards, parityShards)
|
||||
if r.o.inversionCache {
|
||||
r.tree = newInversionTree(dataShards, parityShards)
|
||||
}
|
||||
|
||||
r.parity = make([][]byte, parityShards)
|
||||
for i := range r.parity {
|
||||
@@ -341,8 +418,9 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
}
|
||||
|
||||
if avx2CodeGen && r.o.useAVX2 {
|
||||
sz := r.DataShards * r.ParityShards * 2 * 32
|
||||
r.mPool.New = func() interface{} {
|
||||
return make([]byte, r.Shards*2*32)
|
||||
return make([]byte, sz)
|
||||
}
|
||||
}
|
||||
return &r, err
|
||||
@@ -353,7 +431,7 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
// if there were too few shards to reconstruct the missing data.
|
||||
var ErrTooFewShards = errors.New("too few shards given")
|
||||
|
||||
// Encodes parity for a set of data shards.
|
||||
// Encode parity for a set of data shards.
|
||||
// An array 'shards' containing data shards followed by parity shards.
|
||||
// The number of shards must match the number given to New.
|
||||
// Each shard is a byte array, and they must all be the same size.
|
||||
@@ -373,7 +451,49 @@ func (r *reedSolomon) Encode(shards [][]byte) error {
|
||||
output := shards[r.DataShards:]
|
||||
|
||||
// Do the coding.
|
||||
r.codeSomeShards(r.parity, shards[0:r.DataShards], output, r.ParityShards, len(shards[0]))
|
||||
r.codeSomeShards(r.parity, shards[0:r.DataShards], output[:r.ParityShards], len(shards[0]))
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeIdx will add parity for a single data shard.
|
||||
// Parity shards should start out zeroed. The caller must zero them before first call.
|
||||
// Data shards should only be delivered once. There is no check for this.
|
||||
// The parity shards will always be updated and the data shards will remain the unchanged.
|
||||
func (r *reedSolomon) EncodeIdx(dataShard []byte, idx int, parity [][]byte) error {
|
||||
if len(parity) != r.ParityShards {
|
||||
return ErrTooFewShards
|
||||
}
|
||||
if len(parity) == 0 {
|
||||
return nil
|
||||
}
|
||||
if idx < 0 || idx >= r.DataShards {
|
||||
return ErrInvShardNum
|
||||
}
|
||||
err := checkShards(parity, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(parity[0]) != len(dataShard) {
|
||||
return ErrShardSize
|
||||
}
|
||||
|
||||
// Process using no goroutines for now.
|
||||
start, end := 0, r.o.perRound
|
||||
if end > len(dataShard) {
|
||||
end = len(dataShard)
|
||||
}
|
||||
|
||||
for start < len(dataShard) {
|
||||
in := dataShard[start:end]
|
||||
for iRow := 0; iRow < r.ParityShards; iRow++ {
|
||||
galMulSliceXor(r.parity[iRow][idx], in, parity[iRow][start:end], &r.o)
|
||||
}
|
||||
start = end
|
||||
end += r.o.perRound
|
||||
if end > len(dataShard) {
|
||||
end = len(dataShard)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -421,6 +541,10 @@ func (r *reedSolomon) Update(shards [][]byte, newDatashards [][]byte) error {
|
||||
}
|
||||
|
||||
func (r *reedSolomon) updateParityShards(matrixRows, oldinputs, newinputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
if len(outputs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if r.o.maxGoroutines > 1 && byteCount > r.o.minSplitSize {
|
||||
r.updateParityShardsP(matrixRows, oldinputs, newinputs, outputs, outputCount, byteCount)
|
||||
return
|
||||
@@ -432,7 +556,7 @@ func (r *reedSolomon) updateParityShards(matrixRows, oldinputs, newinputs, outpu
|
||||
continue
|
||||
}
|
||||
oldin := oldinputs[c]
|
||||
// oldinputs data will be change
|
||||
// oldinputs data will be changed
|
||||
sliceXor(in, oldin, &r.o)
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
galMulSliceXor(matrixRows[iRow][c], oldin, outputs[iRow], &r.o)
|
||||
@@ -487,7 +611,13 @@ func (r *reedSolomon) Verify(shards [][]byte) (bool, error) {
|
||||
toCheck := shards[r.DataShards:]
|
||||
|
||||
// Do the checking.
|
||||
return r.checkSomeShards(r.parity, shards[0:r.DataShards], toCheck, r.ParityShards, len(shards[0])), nil
|
||||
return r.checkSomeShards(r.parity, shards[:r.DataShards], toCheck[:r.ParityShards], len(shards[0])), nil
|
||||
}
|
||||
|
||||
func (r *reedSolomon) canAVX2C(byteCount int, inputs, outputs int) bool {
|
||||
return avx2CodeGen && r.o.useAVX2 &&
|
||||
byteCount >= avx2CodeGenMinSize && inputs+outputs >= avx2CodeGenMinShards &&
|
||||
inputs <= maxAvx2Inputs && outputs <= maxAvx2Outputs
|
||||
}
|
||||
|
||||
// Multiplies a subset of rows from a coding matrix by a full set of
|
||||
@@ -499,19 +629,19 @@ func (r *reedSolomon) Verify(shards [][]byte) (bool, error) {
|
||||
// The number of outputs computed, and the
|
||||
// number of matrix rows used, is determined by
|
||||
// outputCount, which is the number of outputs to compute.
|
||||
func (r *reedSolomon) codeSomeShards(matrixRows, inputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
func (r *reedSolomon) codeSomeShards(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
if len(outputs) == 0 {
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case r.o.useAVX512 && r.o.maxGoroutines > 1 && byteCount > r.o.minSplitSize && len(inputs) >= 4 && len(outputs) >= 2:
|
||||
r.codeSomeShardsAvx512P(matrixRows, inputs, outputs, outputCount, byteCount)
|
||||
r.codeSomeShardsAvx512P(matrixRows, inputs, outputs, byteCount)
|
||||
return
|
||||
case r.o.useAVX512 && len(inputs) >= 4 && len(outputs) >= 2:
|
||||
r.codeSomeShardsAvx512(matrixRows, inputs, outputs, outputCount, byteCount)
|
||||
r.codeSomeShardsAvx512(matrixRows, inputs, outputs, byteCount)
|
||||
return
|
||||
case r.o.maxGoroutines > 1 && byteCount > r.o.minSplitSize:
|
||||
r.codeSomeShardsP(matrixRows, inputs, outputs, outputCount, byteCount)
|
||||
case byteCount > r.o.minSplitSize:
|
||||
r.codeSomeShardsP(matrixRows, inputs, outputs, byteCount)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -520,17 +650,50 @@ func (r *reedSolomon) codeSomeShards(matrixRows, inputs, outputs [][]byte, outpu
|
||||
if end > len(inputs[0]) {
|
||||
end = len(inputs[0])
|
||||
}
|
||||
if avx2CodeGen && r.o.useAVX2 && byteCount >= 32 && len(inputs) > 1 && len(outputs) > 1 && len(inputs) <= maxAvx2Inputs && len(outputs) <= maxAvx2Outputs {
|
||||
m := genAvx2Matrix(matrixRows, len(inputs), len(outputs), r.mPool.Get().([]byte))
|
||||
if r.canAVX2C(byteCount, len(inputs), len(outputs)) {
|
||||
m := genAvx2Matrix(matrixRows, len(inputs), 0, len(outputs), r.mPool.Get().([]byte))
|
||||
start += galMulSlicesAvx2(m, inputs, outputs, 0, byteCount)
|
||||
r.mPool.Put(m)
|
||||
end = len(inputs[0])
|
||||
} else if len(inputs)+len(outputs) > avx2CodeGenMinShards && r.canAVX2C(byteCount, maxAvx2Inputs, maxAvx2Outputs) {
|
||||
end = len(inputs[0])
|
||||
inIdx := 0
|
||||
m := r.mPool.Get().([]byte)
|
||||
defer r.mPool.Put(m)
|
||||
ins := inputs
|
||||
for len(ins) > 0 {
|
||||
inPer := ins
|
||||
if len(inPer) > maxAvx2Inputs {
|
||||
inPer = inPer[:maxAvx2Inputs]
|
||||
}
|
||||
outs := outputs
|
||||
outIdx := 0
|
||||
for len(outs) > 0 {
|
||||
outPer := outs
|
||||
if len(outPer) > maxAvx2Outputs {
|
||||
outPer = outPer[:maxAvx2Outputs]
|
||||
}
|
||||
m = genAvx2Matrix(matrixRows[outIdx:], len(inPer), inIdx, len(outPer), m)
|
||||
if inIdx == 0 {
|
||||
galMulSlicesAvx2(m, inPer, outPer, 0, byteCount)
|
||||
} else {
|
||||
galMulSlicesAvx2Xor(m, inPer, outPer, 0, byteCount)
|
||||
}
|
||||
start = byteCount & avxSizeMask
|
||||
outIdx += len(outPer)
|
||||
outs = outs[len(outPer):]
|
||||
}
|
||||
inIdx += len(inPer)
|
||||
ins = ins[len(inPer):]
|
||||
}
|
||||
if start >= end {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for start < len(inputs[0]) {
|
||||
for c := 0; c < r.DataShards; c++ {
|
||||
for c := 0; c < len(inputs); c++ {
|
||||
in := inputs[c][start:end]
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
for iRow := 0; iRow < len(outputs); iRow++ {
|
||||
if c == 0 {
|
||||
galMulSlice(matrixRows[iRow][c], in, outputs[iRow][start:end], &r.o)
|
||||
} else {
|
||||
@@ -548,54 +711,227 @@ func (r *reedSolomon) codeSomeShards(matrixRows, inputs, outputs [][]byte, outpu
|
||||
|
||||
// Perform the same as codeSomeShards, but split the workload into
|
||||
// several goroutines.
|
||||
func (r *reedSolomon) codeSomeShardsP(matrixRows, inputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
func (r *reedSolomon) codeSomeShardsP(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
var wg sync.WaitGroup
|
||||
do := byteCount / r.o.maxGoroutines
|
||||
gor := r.o.maxGoroutines
|
||||
|
||||
var avx2Matrix []byte
|
||||
useAvx2 := r.canAVX2C(byteCount, len(inputs), len(outputs))
|
||||
if useAvx2 {
|
||||
avx2Matrix = genAvx2Matrix(matrixRows, len(inputs), 0, len(outputs), r.mPool.Get().([]byte))
|
||||
defer r.mPool.Put(avx2Matrix)
|
||||
} else if byteCount < 10<<20 && len(inputs)+len(outputs) > avx2CodeGenMinShards &&
|
||||
r.canAVX2C(byteCount/4, maxAvx2Inputs, maxAvx2Outputs) {
|
||||
// It appears there is a switchover point at around 10MB where
|
||||
// Regular processing is faster...
|
||||
r.codeSomeShardsAVXP(matrixRows, inputs, outputs, byteCount)
|
||||
return
|
||||
}
|
||||
|
||||
do := byteCount / gor
|
||||
if do < r.o.minSplitSize {
|
||||
do = r.o.minSplitSize
|
||||
}
|
||||
|
||||
exec := func(start, stop int) {
|
||||
if useAvx2 && stop-start >= 64 {
|
||||
start += galMulSlicesAvx2(avx2Matrix, inputs, outputs, start, stop)
|
||||
}
|
||||
|
||||
lstart, lstop := start, start+r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
for lstart < stop {
|
||||
for c := 0; c < len(inputs); c++ {
|
||||
in := inputs[c][lstart:lstop]
|
||||
for iRow := 0; iRow < len(outputs); iRow++ {
|
||||
if c == 0 {
|
||||
galMulSlice(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
} else {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
}
|
||||
}
|
||||
}
|
||||
lstart = lstop
|
||||
lstop += r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
if gor <= 1 {
|
||||
wg.Add(1)
|
||||
exec(0, byteCount)
|
||||
return
|
||||
}
|
||||
|
||||
// Make sizes divisible by 64
|
||||
do = (do + 63) & (^63)
|
||||
start := 0
|
||||
var avx2Matrix []byte
|
||||
if avx2CodeGen && r.o.useAVX2 && byteCount >= 32 && len(inputs) > 1 && len(outputs) > 1 && len(inputs) <= maxAvx2Inputs && len(outputs) <= maxAvx2Outputs {
|
||||
avx2Matrix = genAvx2Matrix(matrixRows, len(inputs), len(outputs), r.mPool.Get().([]byte))
|
||||
defer r.mPool.Put(avx2Matrix)
|
||||
}
|
||||
for start < byteCount {
|
||||
if start+do > byteCount {
|
||||
do = byteCount - start
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(start, stop int) {
|
||||
if avx2CodeGen && r.o.useAVX2 && stop-start >= 32 && len(inputs) > 1 && len(outputs) > 1 && len(inputs) <= maxAvx2Inputs && len(outputs) <= maxAvx2Outputs {
|
||||
start += galMulSlicesAvx2(avx2Matrix, inputs, outputs, start, stop)
|
||||
go exec(start, start+do)
|
||||
start += do
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Perform the same as codeSomeShards, but split the workload into
|
||||
// several goroutines.
|
||||
func (r *reedSolomon) codeSomeShardsAVXP(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
var wg sync.WaitGroup
|
||||
gor := r.o.maxGoroutines
|
||||
|
||||
type state struct {
|
||||
input [][]byte
|
||||
output [][]byte
|
||||
m []byte
|
||||
first bool
|
||||
}
|
||||
// Make a plan...
|
||||
plan := make([]state, 0, ((len(inputs)+maxAvx2Inputs-1)/maxAvx2Inputs)*((len(outputs)+maxAvx2Outputs-1)/maxAvx2Outputs))
|
||||
|
||||
tmp := r.mPool.Get().([]byte)
|
||||
defer func(b []byte) {
|
||||
r.mPool.Put(b)
|
||||
}(tmp)
|
||||
|
||||
// Flips between input first to output first.
|
||||
// We put the smallest data load in the inner loop.
|
||||
if len(inputs) > len(outputs) {
|
||||
inIdx := 0
|
||||
ins := inputs
|
||||
for len(ins) > 0 {
|
||||
inPer := ins
|
||||
if len(inPer) > maxAvx2Inputs {
|
||||
inPer = inPer[:maxAvx2Inputs]
|
||||
}
|
||||
outs := outputs
|
||||
outIdx := 0
|
||||
for len(outs) > 0 {
|
||||
outPer := outs
|
||||
if len(outPer) > maxAvx2Outputs {
|
||||
outPer = outPer[:maxAvx2Outputs]
|
||||
}
|
||||
// Generate local matrix
|
||||
m := genAvx2Matrix(matrixRows[outIdx:], len(inPer), inIdx, len(outPer), tmp)
|
||||
tmp = tmp[len(m):]
|
||||
plan = append(plan, state{
|
||||
input: inPer,
|
||||
output: outPer,
|
||||
m: m,
|
||||
first: inIdx == 0,
|
||||
})
|
||||
outIdx += len(outPer)
|
||||
outs = outs[len(outPer):]
|
||||
}
|
||||
inIdx += len(inPer)
|
||||
ins = ins[len(inPer):]
|
||||
}
|
||||
} else {
|
||||
outs := outputs
|
||||
outIdx := 0
|
||||
for len(outs) > 0 {
|
||||
outPer := outs
|
||||
if len(outPer) > maxAvx2Outputs {
|
||||
outPer = outPer[:maxAvx2Outputs]
|
||||
}
|
||||
|
||||
lstart, lstop := start, start+r.o.perRound
|
||||
inIdx := 0
|
||||
ins := inputs
|
||||
for len(ins) > 0 {
|
||||
inPer := ins
|
||||
if len(inPer) > maxAvx2Inputs {
|
||||
inPer = inPer[:maxAvx2Inputs]
|
||||
}
|
||||
// Generate local matrix
|
||||
m := genAvx2Matrix(matrixRows[outIdx:], len(inPer), inIdx, len(outPer), tmp)
|
||||
tmp = tmp[len(m):]
|
||||
//fmt.Println("bytes:", len(inPer)*r.o.perRound, "out:", len(outPer)*r.o.perRound)
|
||||
plan = append(plan, state{
|
||||
input: inPer,
|
||||
output: outPer,
|
||||
m: m,
|
||||
first: inIdx == 0,
|
||||
})
|
||||
inIdx += len(inPer)
|
||||
ins = ins[len(inPer):]
|
||||
}
|
||||
outIdx += len(outPer)
|
||||
outs = outs[len(outPer):]
|
||||
}
|
||||
}
|
||||
|
||||
do := byteCount / gor
|
||||
if do < r.o.minSplitSize {
|
||||
do = r.o.minSplitSize
|
||||
}
|
||||
|
||||
exec := func(start, stop int) {
|
||||
lstart, lstop := start, start+r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
for lstart < stop {
|
||||
if lstop-lstart >= minAvx2Size {
|
||||
// Execute plan...
|
||||
for _, p := range plan {
|
||||
if p.first {
|
||||
galMulSlicesAvx2(p.m, p.input, p.output, lstart, lstop)
|
||||
} else {
|
||||
galMulSlicesAvx2Xor(p.m, p.input, p.output, lstart, lstop)
|
||||
}
|
||||
}
|
||||
lstart += (lstop - lstart) & avxSizeMask
|
||||
if lstart == lstop {
|
||||
lstop += r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for c := range inputs {
|
||||
in := inputs[c][lstart:lstop]
|
||||
for iRow := 0; iRow < len(outputs); iRow++ {
|
||||
if c == 0 {
|
||||
galMulSlice(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
} else {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
}
|
||||
}
|
||||
}
|
||||
lstart = lstop
|
||||
lstop += r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
for lstart < stop {
|
||||
for c := 0; c < r.DataShards; c++ {
|
||||
in := inputs[c][lstart:lstop]
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
if c == 0 {
|
||||
galMulSlice(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
} else {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
}
|
||||
}
|
||||
}
|
||||
lstart = lstop
|
||||
lstop += r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}(start, start+do)
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
if gor == 1 {
|
||||
wg.Add(1)
|
||||
exec(0, byteCount)
|
||||
return
|
||||
}
|
||||
|
||||
// Make sizes divisible by 64
|
||||
do = (do + 63) & (^63)
|
||||
start := 0
|
||||
for start < byteCount {
|
||||
if start+do > byteCount {
|
||||
do = byteCount - start
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go exec(start, start+do)
|
||||
start += do
|
||||
}
|
||||
wg.Wait()
|
||||
@@ -604,20 +940,16 @@ func (r *reedSolomon) codeSomeShardsP(matrixRows, inputs, outputs [][]byte, outp
|
||||
// checkSomeShards is mostly the same as codeSomeShards,
|
||||
// except this will check values and return
|
||||
// as soon as a difference is found.
|
||||
func (r *reedSolomon) checkSomeShards(matrixRows, inputs, toCheck [][]byte, outputCount, byteCount int) bool {
|
||||
if r.o.maxGoroutines > 1 && byteCount > r.o.minSplitSize {
|
||||
return r.checkSomeShardsP(matrixRows, inputs, toCheck, outputCount, byteCount)
|
||||
func (r *reedSolomon) checkSomeShards(matrixRows, inputs, toCheck [][]byte, byteCount int) bool {
|
||||
if len(toCheck) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
outputs := make([][]byte, len(toCheck))
|
||||
for i := range outputs {
|
||||
outputs[i] = make([]byte, byteCount)
|
||||
}
|
||||
for c := 0; c < r.DataShards; c++ {
|
||||
in := inputs[c]
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow], &r.o)
|
||||
}
|
||||
}
|
||||
r.codeSomeShards(matrixRows, inputs, outputs, byteCount)
|
||||
|
||||
for i, calc := range outputs {
|
||||
if !bytes.Equal(calc, toCheck[i]) {
|
||||
@@ -627,57 +959,6 @@ func (r *reedSolomon) checkSomeShards(matrixRows, inputs, toCheck [][]byte, outp
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *reedSolomon) checkSomeShardsP(matrixRows, inputs, toCheck [][]byte, outputCount, byteCount int) bool {
|
||||
same := true
|
||||
var mu sync.RWMutex // For above
|
||||
|
||||
var wg sync.WaitGroup
|
||||
do := byteCount / r.o.maxGoroutines
|
||||
if do < r.o.minSplitSize {
|
||||
do = r.o.minSplitSize
|
||||
}
|
||||
// Make sizes divisible by 64
|
||||
do = (do + 63) & (^63)
|
||||
start := 0
|
||||
for start < byteCount {
|
||||
if start+do > byteCount {
|
||||
do = byteCount - start
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(start, do int) {
|
||||
defer wg.Done()
|
||||
outputs := make([][]byte, len(toCheck))
|
||||
for i := range outputs {
|
||||
outputs[i] = make([]byte, do)
|
||||
}
|
||||
for c := 0; c < r.DataShards; c++ {
|
||||
mu.RLock()
|
||||
if !same {
|
||||
mu.RUnlock()
|
||||
return
|
||||
}
|
||||
mu.RUnlock()
|
||||
in := inputs[c][start : start+do]
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow], &r.o)
|
||||
}
|
||||
}
|
||||
|
||||
for i, calc := range outputs {
|
||||
if !bytes.Equal(calc, toCheck[i][start:start+do]) {
|
||||
mu.Lock()
|
||||
same = false
|
||||
mu.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
}(start, do)
|
||||
start += do
|
||||
}
|
||||
wg.Wait()
|
||||
return same
|
||||
}
|
||||
|
||||
// ErrShardNoData will be returned if there are no shards,
|
||||
// or if the length of all shards is zero.
|
||||
var ErrShardNoData = errors.New("no shard data")
|
||||
@@ -732,7 +1013,7 @@ func shardSize(shards [][]byte) int {
|
||||
// The reconstructed shard set is complete, but integrity is not verified.
|
||||
// Use the Verify function to check if data set is ok.
|
||||
func (r *reedSolomon) Reconstruct(shards [][]byte) error {
|
||||
return r.reconstruct(shards, false)
|
||||
return r.reconstruct(shards, false, nil)
|
||||
}
|
||||
|
||||
// ReconstructData will recreate any missing data shards, if possible.
|
||||
@@ -751,19 +1032,39 @@ func (r *reedSolomon) Reconstruct(shards [][]byte) error {
|
||||
// As the reconstructed shard set may contain missing parity shards,
|
||||
// calling the Verify function is likely to fail.
|
||||
func (r *reedSolomon) ReconstructData(shards [][]byte) error {
|
||||
return r.reconstruct(shards, true)
|
||||
return r.reconstruct(shards, true, nil)
|
||||
}
|
||||
|
||||
// ReconstructSome will recreate only requested data shards, if possible.
|
||||
//
|
||||
// Given a list of shards, some of which contain data, fills in the
|
||||
// data shards indicated by true values in the "required" parameter.
|
||||
// The length of "required" array must be equal to DataShards.
|
||||
//
|
||||
// The length of "shards" array must be equal to Shards.
|
||||
// You indicate that a shard is missing by setting it to nil or zero-length.
|
||||
// If a shard is zero-length but has sufficient capacity, that memory will
|
||||
// be used, otherwise a new []byte will be allocated.
|
||||
//
|
||||
// If there are too few shards to reconstruct the missing
|
||||
// ones, ErrTooFewShards will be returned.
|
||||
//
|
||||
// As the reconstructed shard set may contain missing parity shards,
|
||||
// calling the Verify function is likely to fail.
|
||||
func (r *reedSolomon) ReconstructSome(shards [][]byte, required []bool) error {
|
||||
return r.reconstruct(shards, true, required)
|
||||
}
|
||||
|
||||
// reconstruct will recreate the missing data shards, and unless
|
||||
// dataOnly is true, also the missing parity shards
|
||||
//
|
||||
// The length of the array must be equal to Shards.
|
||||
// The length of "shards" array must be equal to Shards.
|
||||
// You indicate that a shard is missing by setting it to nil.
|
||||
//
|
||||
// If there are too few shards to reconstruct the missing
|
||||
// ones, ErrTooFewShards will be returned.
|
||||
func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
if len(shards) != r.Shards {
|
||||
func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool, required []bool) error {
|
||||
if len(shards) != r.Shards || required != nil && len(required) < r.DataShards {
|
||||
return ErrTooFewShards
|
||||
}
|
||||
// Check arguments.
|
||||
@@ -778,15 +1079,19 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
// nothing to do.
|
||||
numberPresent := 0
|
||||
dataPresent := 0
|
||||
missingRequired := 0
|
||||
for i := 0; i < r.Shards; i++ {
|
||||
if len(shards[i]) != 0 {
|
||||
numberPresent++
|
||||
if i < r.DataShards {
|
||||
dataPresent++
|
||||
}
|
||||
} else if required != nil && required[i] {
|
||||
missingRequired++
|
||||
}
|
||||
}
|
||||
if numberPresent == r.Shards || dataOnly && dataPresent == r.DataShards {
|
||||
if numberPresent == r.Shards || dataOnly && dataPresent == r.DataShards ||
|
||||
required != nil && missingRequired == 0 {
|
||||
// Cool. All of the shards data data. We don't
|
||||
// need to do anything.
|
||||
return nil
|
||||
@@ -864,7 +1169,7 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
outputCount := 0
|
||||
|
||||
for iShard := 0; iShard < r.DataShards; iShard++ {
|
||||
if len(shards[iShard]) == 0 {
|
||||
if len(shards[iShard]) == 0 && (required == nil || required[iShard]) {
|
||||
if cap(shards[iShard]) >= shardSize {
|
||||
shards[iShard] = shards[iShard][0:shardSize]
|
||||
} else {
|
||||
@@ -875,7 +1180,7 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
outputCount++
|
||||
}
|
||||
}
|
||||
r.codeSomeShards(matrixRows, subShards, outputs[:outputCount], outputCount, shardSize)
|
||||
r.codeSomeShards(matrixRows, subShards, outputs[:outputCount], shardSize)
|
||||
|
||||
if dataOnly {
|
||||
// Exit out early if we are only interested in the data shards
|
||||
@@ -890,7 +1195,7 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
// data shards were missing.
|
||||
outputCount = 0
|
||||
for iShard := r.DataShards; iShard < r.Shards; iShard++ {
|
||||
if len(shards[iShard]) == 0 {
|
||||
if len(shards[iShard]) == 0 && (required == nil || required[iShard]) {
|
||||
if cap(shards[iShard]) >= shardSize {
|
||||
shards[iShard] = shards[iShard][0:shardSize]
|
||||
} else {
|
||||
@@ -901,7 +1206,7 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
outputCount++
|
||||
}
|
||||
}
|
||||
r.codeSomeShards(matrixRows, shards[:r.DataShards], outputs[:outputCount], outputCount, shardSize)
|
||||
r.codeSomeShards(matrixRows, shards[:r.DataShards], outputs[:outputCount], shardSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -925,6 +1230,7 @@ func (r *reedSolomon) Split(data []byte) ([][]byte, error) {
|
||||
if len(data) == 0 {
|
||||
return nil, ErrShortData
|
||||
}
|
||||
dataLen := len(data)
|
||||
// Calculate number of bytes per data shard.
|
||||
perShard := (len(data) + r.DataShards - 1) / r.DataShards
|
||||
|
||||
@@ -940,6 +1246,10 @@ func (r *reedSolomon) Split(data []byte) ([][]byte, error) {
|
||||
padding = make([]byte, r.Shards*perShard-perShard*fullShards)
|
||||
copy(padding, data[perShard*fullShards:])
|
||||
data = data[0 : perShard*fullShards]
|
||||
} else {
|
||||
for i := dataLen; i < dataLen+r.DataShards; i++ {
|
||||
data[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Split into equal-length shards.
|
||||
|
||||
+242
-101
@@ -12,29 +12,23 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
sm4 acceration
|
||||
sm4 acceleration
|
||||
modified by Jack, 2017 Oct
|
||||
*/
|
||||
|
||||
package sm4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const BlockSize = 16
|
||||
|
||||
var IV=make([]byte,BlockSize)
|
||||
type SM4Key []byte
|
||||
|
||||
type KeySizeError int
|
||||
|
||||
// Cipher is an instance of SM4 encryption.
|
||||
type Sm4Cipher struct {
|
||||
subkeys []uint32
|
||||
@@ -234,101 +228,10 @@ func generateSubKeys(key []byte) []uint32 {
|
||||
return subkeys
|
||||
}
|
||||
|
||||
func EncryptBlock(key SM4Key, dst, src []byte) {
|
||||
subkeys := generateSubKeys(key)
|
||||
cryptBlock(subkeys, make([]uint32, 4), make([]byte, 16), dst, src, false)
|
||||
}
|
||||
|
||||
func DecryptBlock(key SM4Key, dst, src []byte) {
|
||||
subkeys := generateSubKeys(key)
|
||||
cryptBlock(subkeys, make([]uint32, 4), make([]byte, 16), dst, src, true)
|
||||
}
|
||||
|
||||
func ReadKeyFromMem(data []byte, pwd []byte) (SM4Key, error) {
|
||||
block, _ := pem.Decode(data)
|
||||
if block == nil {
|
||||
return nil, errors.New("SM4: pem decode failed")
|
||||
}
|
||||
if x509.IsEncryptedPEMBlock(block) {
|
||||
if block.Type != "SM4 ENCRYPTED KEY" {
|
||||
return nil, errors.New("SM4: unknown type")
|
||||
}
|
||||
if pwd == nil {
|
||||
return nil, errors.New("SM4: need passwd")
|
||||
}
|
||||
data, err := x509.DecryptPEMBlock(block, pwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
if block.Type != "SM4 KEY" {
|
||||
return nil, errors.New("SM4: unknown type")
|
||||
}
|
||||
return block.Bytes, nil
|
||||
}
|
||||
|
||||
func ReadKeyFromPem(FileName string, pwd []byte) (SM4Key, error) {
|
||||
data, err := ioutil.ReadFile(FileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ReadKeyFromMem(data, pwd)
|
||||
}
|
||||
|
||||
func WriteKeytoMem(key SM4Key, pwd []byte) ([]byte, error) {
|
||||
if pwd != nil {
|
||||
block, err := x509.EncryptPEMBlock(rand.Reader,
|
||||
"SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
} else {
|
||||
block := &pem.Block{
|
||||
Type: "SM4 KEY",
|
||||
Bytes: key,
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
}
|
||||
|
||||
func WriteKeyToPem(FileName string, key SM4Key, pwd []byte) (bool, error) {
|
||||
var block *pem.Block
|
||||
|
||||
if pwd != nil {
|
||||
var err error
|
||||
block, err = x509.EncryptPEMBlock(rand.Reader,
|
||||
"SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
block = &pem.Block{
|
||||
Type: "SM4 KEY",
|
||||
Bytes: key,
|
||||
}
|
||||
}
|
||||
file, err := os.Create(FileName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer file.Close()
|
||||
err = pem.Encode(file, block)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (k KeySizeError) Error() string {
|
||||
return "SM4: invalid key size " + strconv.Itoa(int(k))
|
||||
}
|
||||
|
||||
// NewCipher creates and returns a new cipher.Block.
|
||||
func NewCipher(key []byte) (cipher.Block, error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, KeySizeError(len(key))
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
c := new(Sm4Cipher)
|
||||
c.subkeys = generateSubKeys(key)
|
||||
@@ -345,6 +248,244 @@ func (c *Sm4Cipher) Encrypt(dst, src []byte) {
|
||||
cryptBlock(c.subkeys, c.block1, c.block2, dst, src, false)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (c *Sm4Cipher) Decrypt(dst, src []byte) {
|
||||
cryptBlock(c.subkeys, c.block1, c.block2, dst, src, true)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func xor(in, iv []byte) (out []byte) {
|
||||
if len(in) != len(iv) {
|
||||
return nil
|
||||
}
|
||||
|
||||
out = make([]byte, len(in))
|
||||
for i := 0; i < len(in); i++ {
|
||||
out[i] = in[i] ^ iv[i]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func pkcs7Padding(src []byte) []byte {
|
||||
padding := BlockSize - len(src)%BlockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(src, padtext...)
|
||||
}
|
||||
|
||||
func pkcs7UnPadding(src []byte) ([]byte, error) {
|
||||
length := len(src)
|
||||
unpadding := int(src[length-1])
|
||||
if unpadding > BlockSize || unpadding == 0 {
|
||||
return nil, errors.New("Invalid pkcs7 padding (unpadding > BlockSize || unpadding == 0)")
|
||||
}
|
||||
|
||||
pad := src[len(src)-unpadding:]
|
||||
for i := 0; i < unpadding; i++ {
|
||||
if pad[i] != byte(unpadding) {
|
||||
return nil, errors.New("Invalid pkcs7 padding (pad[i] != unpadding)")
|
||||
}
|
||||
}
|
||||
|
||||
return src[:(length - unpadding)], nil
|
||||
}
|
||||
func SetIV(iv []byte)error{
|
||||
if len(iv)!=BlockSize{
|
||||
return errors.New("SM4: invalid iv size")
|
||||
}
|
||||
IV=iv
|
||||
return nil
|
||||
}
|
||||
|
||||
func Sm4Cbc(key []byte, in []byte, mode bool) (out []byte, err error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
var inData []byte
|
||||
if mode {
|
||||
inData = pkcs7Padding(in)
|
||||
} else {
|
||||
inData = in
|
||||
}
|
||||
iv:=make([]byte,BlockSize)
|
||||
copy(iv,IV)
|
||||
out = make([]byte, len(inData))
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mode {
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
in_tmp := xor(inData[i*16:i*16+16], iv)
|
||||
out_tmp := make([]byte, 16)
|
||||
c.Encrypt(out_tmp, in_tmp)
|
||||
copy(out[i*16:i*16+16], out_tmp)
|
||||
iv = out_tmp
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
in_tmp := inData[i*16 : i*16+16]
|
||||
out_tmp := make([]byte, 16)
|
||||
c.Decrypt(out_tmp, in_tmp)
|
||||
out_tmp = xor(out_tmp, iv)
|
||||
copy(out[i*16:i*16+16], out_tmp)
|
||||
iv = in_tmp
|
||||
}
|
||||
out, _ = pkcs7UnPadding(out)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
func Sm4Ecb(key []byte, in []byte, mode bool) (out []byte, err error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
var inData []byte
|
||||
if mode {
|
||||
inData = pkcs7Padding(in)
|
||||
} else {
|
||||
inData = in
|
||||
}
|
||||
out = make([]byte, len(inData))
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mode {
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
in_tmp := inData[i*16 : i*16+16]
|
||||
out_tmp := make([]byte, 16)
|
||||
c.Encrypt(out_tmp, in_tmp)
|
||||
copy(out[i*16:i*16+16], out_tmp)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
in_tmp := inData[i*16 : i*16+16]
|
||||
out_tmp := make([]byte, 16)
|
||||
c.Decrypt(out_tmp, in_tmp)
|
||||
copy(out[i*16:i*16+16], out_tmp)
|
||||
}
|
||||
out, _ = pkcs7UnPadding(out)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
//密码反馈模式(Cipher FeedBack (CFB))
|
||||
//https://blog.csdn.net/zy_strive_2012/article/details/102520356
|
||||
//https://blog.csdn.net/sinat_23338865/article/details/72869841
|
||||
func Sm4CFB(key []byte, in []byte, mode bool) (out []byte, err error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
var inData []byte
|
||||
if mode {
|
||||
inData = pkcs7Padding(in)
|
||||
} else {
|
||||
inData = in
|
||||
}
|
||||
|
||||
out = make([]byte, len(inData))
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
K := make([]byte, BlockSize)
|
||||
cipherBlock := make([]byte, BlockSize)
|
||||
plainBlock := make([]byte, BlockSize)
|
||||
if mode { //加密
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
if i == 0 {
|
||||
c.Encrypt(K, IV)
|
||||
cipherBlock = xor(K[:BlockSize], inData[i*16:i*16+16])
|
||||
copy(out[i*16:i*16+16], cipherBlock)
|
||||
//copy(cipherBlock,out_tmp)
|
||||
continue
|
||||
}
|
||||
c.Encrypt(K, cipherBlock)
|
||||
cipherBlock = xor(K[:BlockSize], inData[i*16:i*16+16])
|
||||
copy(out[i*16:i*16+16], cipherBlock)
|
||||
//copy(cipherBlock,out_tmp)
|
||||
}
|
||||
|
||||
} else { //解密
|
||||
var i int = 0
|
||||
for ; i < len(inData)/16; i++ {
|
||||
if i == 0 {
|
||||
c.Encrypt(K, IV) //这里是加密,而不是调用解密方法Decrypt
|
||||
plainBlock = xor(K[:BlockSize], inData[i*16:i*16+16]) //获取明文分组
|
||||
copy(out[i*16:i*16+16], plainBlock)
|
||||
continue
|
||||
}
|
||||
c.Encrypt(K, inData[(i-1)*16:(i-1)*16+16])
|
||||
plainBlock = xor(K[:BlockSize], inData[i*16:i*16+16]) //获取明文分组
|
||||
copy(out[i*16:i*16+16], plainBlock)
|
||||
|
||||
}
|
||||
|
||||
out, _ = pkcs7UnPadding(out)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
//输出反馈模式(Output feedback, OFB)
|
||||
//https://blog.csdn.net/chengqiuming/article/details/82390910
|
||||
//https://blog.csdn.net/sinat_23338865/article/details/72869841
|
||||
func Sm4OFB(key []byte, in []byte, mode bool) (out []byte, err error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
var inData []byte
|
||||
if mode {
|
||||
inData = pkcs7Padding(in)
|
||||
} else {
|
||||
inData = in
|
||||
}
|
||||
|
||||
out = make([]byte, len(inData))
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
K := make([]byte, BlockSize)
|
||||
cipherBlock := make([]byte, BlockSize)
|
||||
plainBlock := make([]byte, BlockSize)
|
||||
shiftIV := make([]byte, BlockSize)
|
||||
if mode { //加密
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
if i == 0 {
|
||||
c.Encrypt(K, IV)
|
||||
cipherBlock = xor(K[:BlockSize], inData[i*16:i*16+16])
|
||||
copy(out[i*16:i*16+16], cipherBlock)
|
||||
copy(shiftIV, K[:BlockSize])
|
||||
continue
|
||||
}
|
||||
c.Encrypt(K, shiftIV)
|
||||
cipherBlock = xor(K[:BlockSize], inData[i*16:i*16+16])
|
||||
copy(out[i*16:i*16+16], cipherBlock)
|
||||
copy(shiftIV, K[:BlockSize])
|
||||
}
|
||||
|
||||
} else { //解密
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
if i == 0 {
|
||||
c.Encrypt(K, IV) //这里是加密,而不是调用解密方法Decrypt
|
||||
plainBlock = xor(K[:BlockSize], inData[i*16:i*16+16]) //获取明文分组
|
||||
copy(out[i*16:i*16+16], plainBlock)
|
||||
copy(shiftIV, K[:BlockSize])
|
||||
continue
|
||||
}
|
||||
c.Encrypt(K, shiftIV)
|
||||
plainBlock = xor(K[:BlockSize], inData[i*16:i*16+16]) //获取明文分组
|
||||
copy(out[i*16:i*16+16], plainBlock)
|
||||
copy(shiftIV, K[:BlockSize])
|
||||
}
|
||||
out, _ = pkcs7UnPadding(out)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ install:
|
||||
- go get github.com/xtaci/kcp-go
|
||||
|
||||
script:
|
||||
- go test -coverprofile=coverage.txt -covermode=atomic -bench .
|
||||
- go test -coverprofile=coverage.txt -covermode=atomic -bench . -timeout 10m
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package kcp
|
||||
|
||||
const maxAutoTuneSamples = 258
|
||||
|
||||
// pulse represents a 0/1 signal with time sequence
|
||||
type pulse struct {
|
||||
bit bool // 0 or 1
|
||||
seq uint32 // sequence of the signal
|
||||
}
|
||||
|
||||
// autoTune object
|
||||
type autoTune struct {
|
||||
pulses [maxAutoTuneSamples]pulse
|
||||
}
|
||||
|
||||
// Sample adds a signal sample to the pulse buffer
|
||||
func (tune *autoTune) Sample(bit bool, seq uint32) {
|
||||
tune.pulses[seq%maxAutoTuneSamples] = pulse{bit, seq}
|
||||
}
|
||||
|
||||
// Find a period for a given signal
|
||||
// returns -1 if not found
|
||||
//
|
||||
// --- ------
|
||||
// | |
|
||||
// |______________|
|
||||
// Period
|
||||
// Falling Edge Rising Edge
|
||||
func (tune *autoTune) FindPeriod(bit bool) int {
|
||||
// last pulse and initial index setup
|
||||
lastPulse := tune.pulses[0]
|
||||
idx := 1
|
||||
|
||||
// left edge
|
||||
var leftEdge int
|
||||
for ; idx < len(tune.pulses); idx++ {
|
||||
if lastPulse.bit != bit && tune.pulses[idx].bit == bit { // edge found
|
||||
if lastPulse.seq+1 == tune.pulses[idx].seq { // ensure edge continuity
|
||||
leftEdge = idx
|
||||
break
|
||||
}
|
||||
}
|
||||
lastPulse = tune.pulses[idx]
|
||||
}
|
||||
|
||||
// right edge
|
||||
var rightEdge int
|
||||
lastPulse = tune.pulses[leftEdge]
|
||||
idx = leftEdge + 1
|
||||
|
||||
for ; idx < len(tune.pulses); idx++ {
|
||||
if lastPulse.seq+1 == tune.pulses[idx].seq { // ensure pulses in this level monotonic
|
||||
if lastPulse.bit == bit && tune.pulses[idx].bit != bit { // edge found
|
||||
rightEdge = idx
|
||||
break
|
||||
}
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
lastPulse = tune.pulses[idx]
|
||||
}
|
||||
|
||||
return rightEdge - leftEdge
|
||||
}
|
||||
+49
-5
@@ -13,6 +13,7 @@ const (
|
||||
typeData = 0xf1
|
||||
typeParity = 0xf2
|
||||
fecExpire = 60000
|
||||
rxFECMulti = 3 // FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory
|
||||
)
|
||||
|
||||
// fecPacket is a decoded FEC packet
|
||||
@@ -45,21 +46,21 @@ type fecDecoder struct {
|
||||
|
||||
// RS decoder
|
||||
codec reedsolomon.Encoder
|
||||
|
||||
// auto tune fec parameter
|
||||
autoTune autoTune
|
||||
}
|
||||
|
||||
func newFECDecoder(rxlimit, dataShards, parityShards int) *fecDecoder {
|
||||
func newFECDecoder(dataShards, parityShards int) *fecDecoder {
|
||||
if dataShards <= 0 || parityShards <= 0 {
|
||||
return nil
|
||||
}
|
||||
if rxlimit < dataShards+parityShards {
|
||||
return nil
|
||||
}
|
||||
|
||||
dec := new(fecDecoder)
|
||||
dec.rxlimit = rxlimit
|
||||
dec.dataShards = dataShards
|
||||
dec.parityShards = parityShards
|
||||
dec.shardSize = dataShards + parityShards
|
||||
dec.rxlimit = rxFECMulti * dec.shardSize
|
||||
codec, err := reedsolomon.New(dataShards, parityShards)
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -73,6 +74,49 @@ func newFECDecoder(rxlimit, dataShards, parityShards int) *fecDecoder {
|
||||
|
||||
// decode a fec packet
|
||||
func (dec *fecDecoder) decode(in fecPacket) (recovered [][]byte) {
|
||||
// sample to auto FEC tuner
|
||||
if in.flag() == typeData {
|
||||
dec.autoTune.Sample(true, in.seqid())
|
||||
} else {
|
||||
dec.autoTune.Sample(false, in.seqid())
|
||||
}
|
||||
|
||||
// check if FEC parameters is out of sync
|
||||
var shouldTune bool
|
||||
if int(in.seqid())%dec.shardSize < dec.dataShards {
|
||||
if in.flag() != typeData { // expect typeData
|
||||
shouldTune = true
|
||||
}
|
||||
} else {
|
||||
if in.flag() != typeParity {
|
||||
shouldTune = true
|
||||
}
|
||||
}
|
||||
|
||||
if shouldTune {
|
||||
autoDS := dec.autoTune.FindPeriod(true)
|
||||
autoPS := dec.autoTune.FindPeriod(false)
|
||||
|
||||
// edges found, we can tune parameters now
|
||||
if autoDS > 0 && autoPS > 0 && autoDS < 256 && autoPS < 256 {
|
||||
// and make sure it's different
|
||||
if autoDS != dec.dataShards || autoPS != dec.parityShards {
|
||||
dec.dataShards = autoDS
|
||||
dec.parityShards = autoPS
|
||||
dec.shardSize = autoDS + autoPS
|
||||
dec.rxlimit = rxFECMulti * dec.shardSize
|
||||
codec, err := reedsolomon.New(autoDS, autoPS)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
dec.codec = codec
|
||||
dec.decodeCache = make([][]byte, dec.shardSize)
|
||||
dec.flagCache = make([]bool, dec.shardSize)
|
||||
//log.Println("autotune to :", dec.dataShards, dec.parityShards)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// insertion
|
||||
n := len(dec.rx) - 1
|
||||
insertIdx := 0
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ require (
|
||||
github.com/klauspost/reedsolomon v1.9.9
|
||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/templexxx/cpu v0.0.7 // indirect
|
||||
github.com/templexxx/xorsimd v0.4.1
|
||||
github.com/tjfoc/gmsm v1.3.2
|
||||
|
||||
+11
@@ -1,3 +1,5 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
||||
@@ -7,6 +9,11 @@ github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 h1:ULR/QWMgcgRiZLU
|
||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/templexxx/cpu v0.0.1 h1:hY4WdLOgKdc8y13EYklu9OUTXik80BkxHoWvTO6MQQY=
|
||||
github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
||||
github.com/templexxx/cpu v0.0.7 h1:pUEZn8JBy/w5yzdYWgx+0m0xL9uk6j4K91C5kOViAzo=
|
||||
@@ -55,4 +62,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IV
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ const (
|
||||
// monotonic reference time point
|
||||
var refTime time.Time = time.Now()
|
||||
|
||||
// currentMs returns current elasped monotonic milliseconds since program startup
|
||||
func currentMs() uint32 { return uint32(time.Now().Sub(refTime) / time.Millisecond) }
|
||||
// currentMs returns current elapsed monotonic milliseconds since program startup
|
||||
func currentMs() uint32 { return uint32(time.Since(refTime) / time.Millisecond) }
|
||||
|
||||
// output_callback is a prototype which ought capture conn and call conn.Write
|
||||
type output_callback func(buf []byte, size int)
|
||||
|
||||
+2
-11
@@ -18,12 +18,7 @@ func (s *UDPSession) defaultReadLoop() {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
continue
|
||||
}
|
||||
|
||||
if n >= s.headerSize+IKCP_OVERHEAD {
|
||||
s.packetInput(buf[:n])
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
}
|
||||
s.packetInput(buf[:n])
|
||||
} else {
|
||||
s.notifyReadError(errors.WithStack(err))
|
||||
return
|
||||
@@ -35,11 +30,7 @@ func (l *Listener) defaultMonitor() {
|
||||
buf := make([]byte, mtuLimit)
|
||||
for {
|
||||
if n, from, err := l.conn.ReadFrom(buf); err == nil {
|
||||
if n >= l.headerSize+IKCP_OVERHEAD {
|
||||
l.packetInput(buf[:n], from)
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
}
|
||||
l.packetInput(buf[:n], from)
|
||||
} else {
|
||||
l.notifyReadError(errors.WithStack(err))
|
||||
return
|
||||
|
||||
+1
-10
@@ -39,11 +39,6 @@ func (s *UDPSession) readLoop() {
|
||||
continue
|
||||
}
|
||||
|
||||
if msg.N < s.headerSize+IKCP_OVERHEAD {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
continue
|
||||
}
|
||||
|
||||
// source and size has validated
|
||||
s.packetInput(msg.Buffers[0][:msg.N])
|
||||
}
|
||||
@@ -95,11 +90,7 @@ func (l *Listener) monitor() {
|
||||
if count, err := xconn.ReadBatch(msgs, 0); err == nil {
|
||||
for i := 0; i < count; i++ {
|
||||
msg := &msgs[i]
|
||||
if msg.N >= l.headerSize+IKCP_OVERHEAD {
|
||||
l.packetInput(msg.Buffers[0][:msg.N], msg.Addr)
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
}
|
||||
l.packetInput(msg.Buffers[0][:msg.N], msg.Addr)
|
||||
}
|
||||
} else {
|
||||
// compatibility issue:
|
||||
|
||||
+68
-81
@@ -35,9 +35,6 @@ const (
|
||||
// maximum packet size
|
||||
mtuLimit = 1500
|
||||
|
||||
// FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory
|
||||
rxFECMulti = 3
|
||||
|
||||
// accept backlog
|
||||
acceptBacklog = 128
|
||||
)
|
||||
@@ -155,7 +152,7 @@ func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn
|
||||
}
|
||||
|
||||
// FEC codec initialization
|
||||
sess.fecDecoder = newFECDecoder(rxFECMulti*(dataShards+parityShards), dataShards, parityShards)
|
||||
sess.fecDecoder = newFECDecoder(dataShards, parityShards)
|
||||
if sess.block != nil {
|
||||
sess.fecEncoder = newFECEncoder(dataShards, parityShards, cryptHeaderSize)
|
||||
} else {
|
||||
@@ -216,7 +213,7 @@ func (s *UDPSession) Read(b []byte) (n int, err error) {
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// if necessary resize the stream buffer to guarantee a sufficent buffer space
|
||||
// if necessary resize the stream buffer to guarantee a sufficient buffer space
|
||||
if cap(s.recvbuf) < size {
|
||||
s.recvbuf = make([]byte, size)
|
||||
}
|
||||
@@ -240,7 +237,7 @@ func (s *UDPSession) Read(b []byte) (n int, err error) {
|
||||
return 0, errors.WithStack(errTimeout)
|
||||
}
|
||||
|
||||
delay := s.rd.Sub(time.Now())
|
||||
delay := time.Until(s.rd)
|
||||
timeout = time.NewTimer(delay)
|
||||
c = timeout.C
|
||||
}
|
||||
@@ -311,7 +308,7 @@ func (s *UDPSession) WriteBuffers(v [][]byte) (n int, err error) {
|
||||
s.mu.Unlock()
|
||||
return 0, errors.WithStack(errTimeout)
|
||||
}
|
||||
delay := s.wd.Sub(time.Now())
|
||||
delay := time.Until(s.wd)
|
||||
timeout = time.NewTimer(delay)
|
||||
c = timeout.C
|
||||
}
|
||||
@@ -343,7 +340,6 @@ func (s *UDPSession) uncork() {
|
||||
}
|
||||
s.txqueue = s.txqueue[:0]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes the connection.
|
||||
@@ -655,22 +651,22 @@ func (s *UDPSession) notifyWriteError(err error) {
|
||||
|
||||
// packet input stage
|
||||
func (s *UDPSession) packetInput(data []byte) {
|
||||
dataValid := false
|
||||
if s.block != nil {
|
||||
decrypted := false
|
||||
if s.block != nil && len(data) >= cryptHeaderSize {
|
||||
s.block.Decrypt(data, data)
|
||||
data = data[nonceSize:]
|
||||
checksum := crc32.ChecksumIEEE(data[crcSize:])
|
||||
if checksum == binary.LittleEndian.Uint32(data) {
|
||||
data = data[crcSize:]
|
||||
dataValid = true
|
||||
decrypted = true
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1)
|
||||
}
|
||||
} else if s.block == nil {
|
||||
dataValid = true
|
||||
decrypted = true
|
||||
}
|
||||
|
||||
if dataValid {
|
||||
if decrypted && len(data) >= IKCP_OVERHEAD {
|
||||
s.kcpInput(data)
|
||||
}
|
||||
}
|
||||
@@ -678,57 +674,58 @@ func (s *UDPSession) packetInput(data []byte) {
|
||||
func (s *UDPSession) kcpInput(data []byte) {
|
||||
var kcpInErrors, fecErrs, fecRecovered, fecParityShards uint64
|
||||
|
||||
if s.fecDecoder != nil {
|
||||
if len(data) > fecHeaderSize { // must be larger than fec header size
|
||||
fecFlag := binary.LittleEndian.Uint16(data[4:])
|
||||
if fecFlag == typeData || fecFlag == typeParity { // 16bit kcp cmd [81-84] and frg [0-255] will not overlap with FEC type 0x00f1 0x00f2
|
||||
if len(data) >= fecHeaderSizePlus2 {
|
||||
f := fecPacket(data)
|
||||
if f.flag() == typeData || f.flag() == typeParity { // header check
|
||||
if f.flag() == typeParity {
|
||||
fecParityShards++
|
||||
}
|
||||
if f.flag() == typeParity {
|
||||
fecParityShards++
|
||||
}
|
||||
|
||||
// lock
|
||||
s.mu.Lock()
|
||||
recovers := s.fecDecoder.decode(f)
|
||||
if f.flag() == typeData {
|
||||
if ret := s.kcp.Input(data[fecHeaderSizePlus2:], true, s.ackNoDelay); ret != 0 {
|
||||
kcpInErrors++
|
||||
}
|
||||
// lock
|
||||
s.mu.Lock()
|
||||
// if fecDecoder is not initialized, create one with default parameter
|
||||
if s.fecDecoder == nil {
|
||||
s.fecDecoder = newFECDecoder(1, 1)
|
||||
}
|
||||
recovers := s.fecDecoder.decode(f)
|
||||
if f.flag() == typeData {
|
||||
if ret := s.kcp.Input(data[fecHeaderSizePlus2:], true, s.ackNoDelay); ret != 0 {
|
||||
kcpInErrors++
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range recovers {
|
||||
if len(r) >= 2 { // must be larger than 2bytes
|
||||
sz := binary.LittleEndian.Uint16(r)
|
||||
if int(sz) <= len(r) && sz >= 2 {
|
||||
if ret := s.kcp.Input(r[2:sz], false, s.ackNoDelay); ret == 0 {
|
||||
fecRecovered++
|
||||
} else {
|
||||
kcpInErrors++
|
||||
}
|
||||
for _, r := range recovers {
|
||||
if len(r) >= 2 { // must be larger than 2bytes
|
||||
sz := binary.LittleEndian.Uint16(r)
|
||||
if int(sz) <= len(r) && sz >= 2 {
|
||||
if ret := s.kcp.Input(r[2:sz], false, s.ackNoDelay); ret == 0 {
|
||||
fecRecovered++
|
||||
} else {
|
||||
fecErrs++
|
||||
kcpInErrors++
|
||||
}
|
||||
} else {
|
||||
fecErrs++
|
||||
}
|
||||
// recycle the recovers
|
||||
xmitBuf.Put(r)
|
||||
} else {
|
||||
fecErrs++
|
||||
}
|
||||
|
||||
// to notify the readers to receive the data
|
||||
if n := s.kcp.PeekSize(); n > 0 {
|
||||
s.notifyReadEvent()
|
||||
}
|
||||
// to notify the writers
|
||||
waitsnd := s.kcp.WaitSnd()
|
||||
if waitsnd < int(s.kcp.snd_wnd) && waitsnd < int(s.kcp.rmt_wnd) {
|
||||
s.notifyWriteEvent()
|
||||
}
|
||||
|
||||
s.uncork()
|
||||
s.mu.Unlock()
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
// recycle the recovers
|
||||
xmitBuf.Put(r)
|
||||
}
|
||||
|
||||
// to notify the readers to receive the data
|
||||
if n := s.kcp.PeekSize(); n > 0 {
|
||||
s.notifyReadEvent()
|
||||
}
|
||||
// to notify the writers
|
||||
waitsnd := s.kcp.WaitSnd()
|
||||
if waitsnd < int(s.kcp.snd_wnd) && waitsnd < int(s.kcp.rmt_wnd) {
|
||||
s.notifyWriteEvent()
|
||||
}
|
||||
|
||||
s.uncork()
|
||||
s.mu.Unlock()
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
}
|
||||
@@ -771,7 +768,6 @@ type (
|
||||
block BlockCrypt // block encryption
|
||||
dataShards int // FEC data shard
|
||||
parityShards int // FEC parity shard
|
||||
fecDecoder *fecDecoder // FEC mock initialization
|
||||
conn net.PacketConn // the underlying packet connection
|
||||
ownConn bool // true if we created conn internally, false if provided by caller
|
||||
|
||||
@@ -779,7 +775,6 @@ type (
|
||||
sessionLock sync.RWMutex
|
||||
chAccepts chan *UDPSession // Listen() backlog
|
||||
chSessionClosed chan net.Addr // session close queue
|
||||
headerSize int // the additional header to a KCP frame
|
||||
|
||||
die chan struct{} // notify the listener has closed
|
||||
dieOnce sync.Once
|
||||
@@ -795,43 +790,45 @@ type (
|
||||
|
||||
// packet input stage
|
||||
func (l *Listener) packetInput(data []byte, addr net.Addr) {
|
||||
dataValid := false
|
||||
if l.block != nil {
|
||||
decrypted := false
|
||||
if l.block != nil && len(data) >= cryptHeaderSize {
|
||||
l.block.Decrypt(data, data)
|
||||
data = data[nonceSize:]
|
||||
checksum := crc32.ChecksumIEEE(data[crcSize:])
|
||||
if checksum == binary.LittleEndian.Uint32(data) {
|
||||
data = data[crcSize:]
|
||||
dataValid = true
|
||||
decrypted = true
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1)
|
||||
}
|
||||
} else if l.block == nil {
|
||||
dataValid = true
|
||||
decrypted = true
|
||||
}
|
||||
|
||||
if dataValid {
|
||||
if decrypted && len(data) >= IKCP_OVERHEAD {
|
||||
l.sessionLock.RLock()
|
||||
s, ok := l.sessions[addr.String()]
|
||||
l.sessionLock.RUnlock()
|
||||
|
||||
var conv, sn uint32
|
||||
convValid := false
|
||||
if l.fecDecoder != nil {
|
||||
isfec := binary.LittleEndian.Uint16(data[4:])
|
||||
if isfec == typeData {
|
||||
convRecovered := false
|
||||
fecFlag := binary.LittleEndian.Uint16(data[4:])
|
||||
if fecFlag == typeData || fecFlag == typeParity { // 16bit kcp cmd [81-84] and frg [0-255] will not overlap with FEC type 0x00f1 0x00f2
|
||||
// packet with FEC
|
||||
if fecFlag == typeData && len(data) >= fecHeaderSizePlus2+IKCP_OVERHEAD {
|
||||
conv = binary.LittleEndian.Uint32(data[fecHeaderSizePlus2:])
|
||||
sn = binary.LittleEndian.Uint32(data[fecHeaderSizePlus2+IKCP_SN_OFFSET:])
|
||||
convValid = true
|
||||
convRecovered = true
|
||||
}
|
||||
} else {
|
||||
// packet without FEC
|
||||
conv = binary.LittleEndian.Uint32(data)
|
||||
sn = binary.LittleEndian.Uint32(data[IKCP_SN_OFFSET:])
|
||||
convValid = true
|
||||
convRecovered = true
|
||||
}
|
||||
|
||||
if ok { // existing connection
|
||||
if !convValid || conv == s.kcp.conv { // parity or valid data shard
|
||||
if !convRecovered || conv == s.kcp.conv { // parity data or valid conversation
|
||||
s.kcpInput(data)
|
||||
} else if sn == 0 { // should replace current connection
|
||||
s.Close()
|
||||
@@ -839,7 +836,7 @@ func (l *Listener) packetInput(data []byte, addr net.Addr) {
|
||||
}
|
||||
}
|
||||
|
||||
if s == nil && convValid { // new session
|
||||
if s == nil && convRecovered { // new session
|
||||
if len(l.chAccepts) < cap(l.chAccepts) { // do not let the new sessions overwhelm accept queue
|
||||
s := newUDPSession(conv, l.dataShards, l.parityShards, l, l.conn, false, addr, l.block)
|
||||
s.kcpInput(data)
|
||||
@@ -917,7 +914,7 @@ func (l *Listener) Accept() (net.Conn, error) {
|
||||
func (l *Listener) AcceptKCP() (*UDPSession, error) {
|
||||
var timeout <-chan time.Time
|
||||
if tdeadline, ok := l.rd.Load().(time.Time); ok && !tdeadline.IsZero() {
|
||||
timeout = time.After(tdeadline.Sub(time.Now()))
|
||||
timeout = time.After(time.Until(tdeadline))
|
||||
}
|
||||
|
||||
select {
|
||||
@@ -988,7 +985,7 @@ func Listen(laddr string) (net.Listener, error) { return ListenWithOptions(laddr
|
||||
//
|
||||
// 'block' is the block encryption algorithm to encrypt packets.
|
||||
//
|
||||
// 'dataShards', 'parityShards' specifiy how many parity packets will be generated following the data packets.
|
||||
// 'dataShards', 'parityShards' specify how many parity packets will be generated following the data packets.
|
||||
//
|
||||
// Check https://github.com/klauspost/reedsolomon for details
|
||||
func ListenWithOptions(laddr string, block BlockCrypt, dataShards, parityShards int) (*Listener, error) {
|
||||
@@ -1020,17 +1017,7 @@ func serveConn(block BlockCrypt, dataShards, parityShards int, conn net.PacketCo
|
||||
l.dataShards = dataShards
|
||||
l.parityShards = parityShards
|
||||
l.block = block
|
||||
l.fecDecoder = newFECDecoder(rxFECMulti*(dataShards+parityShards), dataShards, parityShards)
|
||||
l.chSocketReadError = make(chan struct{})
|
||||
|
||||
// calculate header size
|
||||
if l.block != nil {
|
||||
l.headerSize += cryptHeaderSize
|
||||
}
|
||||
if l.fecDecoder != nil {
|
||||
l.headerSize += fecHeaderSizePlus2
|
||||
}
|
||||
|
||||
go l.monitor()
|
||||
return l, nil
|
||||
}
|
||||
@@ -1042,7 +1029,7 @@ func Dial(raddr string) (net.Conn, error) { return DialWithOptions(raddr, nil, 0
|
||||
//
|
||||
// 'block' is the block encryption algorithm to encrypt packets.
|
||||
//
|
||||
// 'dataShards', 'parityShards' specifiy how many parity packets will be generated following the data packets.
|
||||
// 'dataShards', 'parityShards' specify how many parity packets will be generated following the data packets.
|
||||
//
|
||||
// Check https://github.com/klauspost/reedsolomon for details
|
||||
func DialWithOptions(raddr string, block BlockCrypt, dataShards, parityShards int) (*UDPSession, error) {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ type Snmp struct {
|
||||
RetransSegs uint64 // accmulated retransmited segments
|
||||
FastRetransSegs uint64 // accmulated fast retransmitted segments
|
||||
EarlyRetransSegs uint64 // accmulated early retransmitted segments
|
||||
LostSegs uint64 // number of segs infered as lost
|
||||
LostSegs uint64 // number of segs inferred as lost
|
||||
RepeatSegs uint64 // number of segs duplicated
|
||||
FECRecovered uint64 // correct packets recovered from FEC
|
||||
FECErrs uint64 // incorrect packets recovered from FEC
|
||||
|
||||
+3
@@ -1,3 +1,6 @@
|
||||
arch:
|
||||
- amd64
|
||||
- ppc64le
|
||||
language: go
|
||||
go:
|
||||
- 1.9.x
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
<img src="mux.jpg" alt="smux" height="120px" />
|
||||
|
||||
[1]: https://godoc.org/github.com/xtaci/smux?status.svg
|
||||
[2]: https://pkg.go.dev/github.com/xtaci/smux
|
||||
[2]: https://godoc.org/github.com/xtaci/smux
|
||||
[3]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||
[4]: LICENSE
|
||||
[5]: https://travis-ci.org/xtaci/smux.svg?branch=master
|
||||
@@ -34,7 +34,7 @@ Smux ( **S**imple **MU**ltiple**X**ing) is a multiplexing library for Golang. It
|
||||
|
||||
## Documentation
|
||||
|
||||
For complete documentation, see the associated [Godoc](https://pkg.go.dev/github.com/xtaci/smux).
|
||||
For complete documentation, see the associated [Godoc](https://godoc.org/github.com/xtaci/smux).
|
||||
|
||||
## Benchmark
|
||||
```
|
||||
|
||||
+10
-5
@@ -17,6 +17,9 @@ type Config struct {
|
||||
// SMUX Protocol version, support 1,2
|
||||
Version int
|
||||
|
||||
// Disabled keepalive
|
||||
KeepAliveDisabled bool
|
||||
|
||||
// KeepAliveInterval is how often to send a NOP command to the remote
|
||||
KeepAliveInterval time.Duration
|
||||
|
||||
@@ -54,11 +57,13 @@ func VerifyConfig(config *Config) error {
|
||||
if !(config.Version == 1 || config.Version == 2) {
|
||||
return errors.New("unsupported protocol version")
|
||||
}
|
||||
if config.KeepAliveInterval == 0 {
|
||||
return errors.New("keep-alive interval must be positive")
|
||||
}
|
||||
if config.KeepAliveTimeout < config.KeepAliveInterval {
|
||||
return fmt.Errorf("keep-alive timeout must be larger than keep-alive interval")
|
||||
if !config.KeepAliveDisabled {
|
||||
if config.KeepAliveInterval == 0 {
|
||||
return errors.New("keep-alive interval must be positive")
|
||||
}
|
||||
if config.KeepAliveTimeout < config.KeepAliveInterval {
|
||||
return fmt.Errorf("keep-alive timeout must be larger than keep-alive interval")
|
||||
}
|
||||
}
|
||||
if config.MaxFrameSize <= 0 {
|
||||
return errors.New("max frame size must be positive")
|
||||
|
||||
+5
-3
@@ -24,7 +24,7 @@ var (
|
||||
)
|
||||
|
||||
type writeRequest struct {
|
||||
prio uint64
|
||||
prio uint32
|
||||
frame Frame
|
||||
result chan writeResult
|
||||
}
|
||||
@@ -104,7 +104,9 @@ func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session {
|
||||
go s.shaperLoop()
|
||||
go s.recvLoop()
|
||||
go s.sendLoop()
|
||||
go s.keepalive()
|
||||
if !config.KeepAliveDisabled {
|
||||
go s.keepalive()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -494,7 +496,7 @@ func (s *Session) writeFrame(f Frame) (n int, err error) {
|
||||
}
|
||||
|
||||
// internal writeFrame version to support deadline used in keepalive
|
||||
func (s *Session) writeFrameInternal(f Frame, deadline <-chan time.Time, prio uint64) (int, error) {
|
||||
func (s *Session) writeFrameInternal(f Frame, deadline <-chan time.Time, prio uint32) (int, error) {
|
||||
req := writeRequest{
|
||||
prio: prio,
|
||||
frame: f,
|
||||
|
||||
+5
-1
@@ -1,9 +1,13 @@
|
||||
package smux
|
||||
|
||||
func _itimediff(later, earlier uint32) int32 {
|
||||
return (int32)(later - earlier)
|
||||
}
|
||||
|
||||
type shaperHeap []writeRequest
|
||||
|
||||
func (h shaperHeap) Len() int { return len(h) }
|
||||
func (h shaperHeap) Less(i, j int) bool { return h[i].prio < h[j].prio }
|
||||
func (h shaperHeap) Less(i, j int) bool { return _itimediff(h[j].prio, h[i].prio) > 0 }
|
||||
func (h shaperHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||
func (h *shaperHeap) Push(x interface{}) { *h = append(*h, x.(writeRequest)) }
|
||||
|
||||
|
||||
+8
-2
@@ -272,6 +272,12 @@ func (s *Stream) waitRead() error {
|
||||
case <-s.chReadEvent:
|
||||
return nil
|
||||
case <-s.chFinEvent:
|
||||
// BUG(xtaci): Fix for https://github.com/xtaci/smux/issues/82
|
||||
s.bufferLock.Lock()
|
||||
defer s.bufferLock.Unlock()
|
||||
if len(s.buffers) > 0 {
|
||||
return nil
|
||||
}
|
||||
return io.EOF
|
||||
case <-s.sess.chSocketReadError:
|
||||
return s.sess.socketReadError.Load().(error)
|
||||
@@ -319,7 +325,7 @@ func (s *Stream) Write(b []byte) (n int, err error) {
|
||||
}
|
||||
frame.data = bts[:sz]
|
||||
bts = bts[sz:]
|
||||
n, err := s.sess.writeFrameInternal(frame, deadline, uint64(s.numWritten))
|
||||
n, err := s.sess.writeFrameInternal(frame, deadline, s.numWritten)
|
||||
s.numWritten++
|
||||
sent += n
|
||||
if err != nil {
|
||||
@@ -387,7 +393,7 @@ func (s *Stream) writeV2(b []byte) (n int, err error) {
|
||||
}
|
||||
frame.data = bts[:sz]
|
||||
bts = bts[sz:]
|
||||
n, err := s.sess.writeFrameInternal(frame, deadline, uint64(atomic.LoadUint32(&s.numWritten)))
|
||||
n, err := s.sess.writeFrameInternal(frame, deadline, atomic.LoadUint32(&s.numWritten))
|
||||
atomic.AddUint32(&s.numWritten, uint32(sz))
|
||||
sent += n
|
||||
if err != nil {
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
// Package subtle implements functions that are often useful in cryptographic
|
||||
// code but require careful thought to use correctly.
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
// Copyright 2018 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
|
||||
|
||||
// Package subtle implements functions that are often useful in cryptographic
|
||||
// code but require careful thought to use correctly.
|
||||
package subtle // import "golang.org/x/crypto/internal/subtle"
|
||||
|
||||
// This is the Google App Engine standard variant based on reflect
|
||||
// because the unsafe package and cgo are disallowed.
|
||||
|
||||
import "reflect"
|
||||
|
||||
// AnyOverlap reports whether x and y share memory at any (not necessarily
|
||||
// corresponding) index. The memory beyond the slice length is ignored.
|
||||
func AnyOverlap(x, y []byte) bool {
|
||||
return len(x) > 0 && len(y) > 0 &&
|
||||
reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() &&
|
||||
reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer()
|
||||
}
|
||||
|
||||
// InexactOverlap reports whether x and y share memory at any non-corresponding
|
||||
// index. The memory beyond the slice length is ignored. Note that x and y can
|
||||
// have different lengths and still not have any inexact overlap.
|
||||
//
|
||||
// InexactOverlap can be used to implement the requirements of the crypto/cipher
|
||||
// AEAD, Block, BlockMode and Stream interfaces.
|
||||
func InexactOverlap(x, y []byte) bool {
|
||||
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
|
||||
return false
|
||||
}
|
||||
return AnyOverlap(x, y)
|
||||
}
|
||||
+1
-1
@@ -32,7 +32,7 @@ import (
|
||||
// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
|
||||
// doing:
|
||||
//
|
||||
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
|
||||
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
|
||||
//
|
||||
// Remember to get a good random salt. At least 8 bytes is recommended by the
|
||||
// RFC.
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
//go:build amd64 && !purego && gc
|
||||
// +build amd64,!purego,gc
|
||||
|
||||
package salsa
|
||||
|
||||
|
||||
+118
-120
@@ -2,13 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
//go:build amd64 && !purego && gc
|
||||
// +build amd64,!purego,gc
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
// func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte)
|
||||
// This needs up to 64 bytes at 360(SP); hence the non-obvious frame size.
|
||||
// This needs up to 64 bytes at 360(R12); hence the non-obvious frame size.
|
||||
TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVQ out+0(FP),DI
|
||||
MOVQ in+8(FP),SI
|
||||
@@ -17,10 +18,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVQ key+32(FP),R8
|
||||
|
||||
MOVQ SP,R12
|
||||
MOVQ SP,R9
|
||||
ADDQ $31, R9
|
||||
ANDQ $~31, R9
|
||||
MOVQ R9, SP
|
||||
ADDQ $31, R12
|
||||
ANDQ $~31, R12
|
||||
|
||||
MOVQ DX,R9
|
||||
MOVQ CX,DX
|
||||
@@ -32,116 +31,116 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL 0(R10),R8
|
||||
MOVL 0(DX),AX
|
||||
MOVL 16(R10),R11
|
||||
MOVL CX,0(SP)
|
||||
MOVL R8, 4 (SP)
|
||||
MOVL AX, 8 (SP)
|
||||
MOVL R11, 12 (SP)
|
||||
MOVL CX,0(R12)
|
||||
MOVL R8, 4 (R12)
|
||||
MOVL AX, 8 (R12)
|
||||
MOVL R11, 12 (R12)
|
||||
MOVL 8(DX),CX
|
||||
MOVL 24(R10),R8
|
||||
MOVL 4(R10),AX
|
||||
MOVL 4(DX),R11
|
||||
MOVL CX,16(SP)
|
||||
MOVL R8, 20 (SP)
|
||||
MOVL AX, 24 (SP)
|
||||
MOVL R11, 28 (SP)
|
||||
MOVL CX,16(R12)
|
||||
MOVL R8, 20 (R12)
|
||||
MOVL AX, 24 (R12)
|
||||
MOVL R11, 28 (R12)
|
||||
MOVL 12(DX),CX
|
||||
MOVL 12(R10),DX
|
||||
MOVL 28(R10),R8
|
||||
MOVL 8(R10),AX
|
||||
MOVL DX,32(SP)
|
||||
MOVL CX, 36 (SP)
|
||||
MOVL R8, 40 (SP)
|
||||
MOVL AX, 44 (SP)
|
||||
MOVL DX,32(R12)
|
||||
MOVL CX, 36 (R12)
|
||||
MOVL R8, 40 (R12)
|
||||
MOVL AX, 44 (R12)
|
||||
MOVQ $1634760805,DX
|
||||
MOVQ $857760878,CX
|
||||
MOVQ $2036477234,R8
|
||||
MOVQ $1797285236,AX
|
||||
MOVL DX,48(SP)
|
||||
MOVL CX, 52 (SP)
|
||||
MOVL R8, 56 (SP)
|
||||
MOVL AX, 60 (SP)
|
||||
MOVL DX,48(R12)
|
||||
MOVL CX, 52 (R12)
|
||||
MOVL R8, 56 (R12)
|
||||
MOVL AX, 60 (R12)
|
||||
CMPQ R9,$256
|
||||
JB BYTESBETWEEN1AND255
|
||||
MOVOA 48(SP),X0
|
||||
MOVOA 48(R12),X0
|
||||
PSHUFL $0X55,X0,X1
|
||||
PSHUFL $0XAA,X0,X2
|
||||
PSHUFL $0XFF,X0,X3
|
||||
PSHUFL $0X00,X0,X0
|
||||
MOVOA X1,64(SP)
|
||||
MOVOA X2,80(SP)
|
||||
MOVOA X3,96(SP)
|
||||
MOVOA X0,112(SP)
|
||||
MOVOA 0(SP),X0
|
||||
MOVOA X1,64(R12)
|
||||
MOVOA X2,80(R12)
|
||||
MOVOA X3,96(R12)
|
||||
MOVOA X0,112(R12)
|
||||
MOVOA 0(R12),X0
|
||||
PSHUFL $0XAA,X0,X1
|
||||
PSHUFL $0XFF,X0,X2
|
||||
PSHUFL $0X00,X0,X3
|
||||
PSHUFL $0X55,X0,X0
|
||||
MOVOA X1,128(SP)
|
||||
MOVOA X2,144(SP)
|
||||
MOVOA X3,160(SP)
|
||||
MOVOA X0,176(SP)
|
||||
MOVOA 16(SP),X0
|
||||
MOVOA X1,128(R12)
|
||||
MOVOA X2,144(R12)
|
||||
MOVOA X3,160(R12)
|
||||
MOVOA X0,176(R12)
|
||||
MOVOA 16(R12),X0
|
||||
PSHUFL $0XFF,X0,X1
|
||||
PSHUFL $0X55,X0,X2
|
||||
PSHUFL $0XAA,X0,X0
|
||||
MOVOA X1,192(SP)
|
||||
MOVOA X2,208(SP)
|
||||
MOVOA X0,224(SP)
|
||||
MOVOA 32(SP),X0
|
||||
MOVOA X1,192(R12)
|
||||
MOVOA X2,208(R12)
|
||||
MOVOA X0,224(R12)
|
||||
MOVOA 32(R12),X0
|
||||
PSHUFL $0X00,X0,X1
|
||||
PSHUFL $0XAA,X0,X2
|
||||
PSHUFL $0XFF,X0,X0
|
||||
MOVOA X1,240(SP)
|
||||
MOVOA X2,256(SP)
|
||||
MOVOA X0,272(SP)
|
||||
MOVOA X1,240(R12)
|
||||
MOVOA X2,256(R12)
|
||||
MOVOA X0,272(R12)
|
||||
BYTESATLEAST256:
|
||||
MOVL 16(SP),DX
|
||||
MOVL 36 (SP),CX
|
||||
MOVL DX,288(SP)
|
||||
MOVL CX,304(SP)
|
||||
MOVL 16(R12),DX
|
||||
MOVL 36 (R12),CX
|
||||
MOVL DX,288(R12)
|
||||
MOVL CX,304(R12)
|
||||
SHLQ $32,CX
|
||||
ADDQ CX,DX
|
||||
ADDQ $1,DX
|
||||
MOVQ DX,CX
|
||||
SHRQ $32,CX
|
||||
MOVL DX, 292 (SP)
|
||||
MOVL CX, 308 (SP)
|
||||
MOVL DX, 292 (R12)
|
||||
MOVL CX, 308 (R12)
|
||||
ADDQ $1,DX
|
||||
MOVQ DX,CX
|
||||
SHRQ $32,CX
|
||||
MOVL DX, 296 (SP)
|
||||
MOVL CX, 312 (SP)
|
||||
MOVL DX, 296 (R12)
|
||||
MOVL CX, 312 (R12)
|
||||
ADDQ $1,DX
|
||||
MOVQ DX,CX
|
||||
SHRQ $32,CX
|
||||
MOVL DX, 300 (SP)
|
||||
MOVL CX, 316 (SP)
|
||||
MOVL DX, 300 (R12)
|
||||
MOVL CX, 316 (R12)
|
||||
ADDQ $1,DX
|
||||
MOVQ DX,CX
|
||||
SHRQ $32,CX
|
||||
MOVL DX,16(SP)
|
||||
MOVL CX, 36 (SP)
|
||||
MOVQ R9,352(SP)
|
||||
MOVL DX,16(R12)
|
||||
MOVL CX, 36 (R12)
|
||||
MOVQ R9,352(R12)
|
||||
MOVQ $20,DX
|
||||
MOVOA 64(SP),X0
|
||||
MOVOA 80(SP),X1
|
||||
MOVOA 96(SP),X2
|
||||
MOVOA 256(SP),X3
|
||||
MOVOA 272(SP),X4
|
||||
MOVOA 128(SP),X5
|
||||
MOVOA 144(SP),X6
|
||||
MOVOA 176(SP),X7
|
||||
MOVOA 192(SP),X8
|
||||
MOVOA 208(SP),X9
|
||||
MOVOA 224(SP),X10
|
||||
MOVOA 304(SP),X11
|
||||
MOVOA 112(SP),X12
|
||||
MOVOA 160(SP),X13
|
||||
MOVOA 240(SP),X14
|
||||
MOVOA 288(SP),X15
|
||||
MOVOA 64(R12),X0
|
||||
MOVOA 80(R12),X1
|
||||
MOVOA 96(R12),X2
|
||||
MOVOA 256(R12),X3
|
||||
MOVOA 272(R12),X4
|
||||
MOVOA 128(R12),X5
|
||||
MOVOA 144(R12),X6
|
||||
MOVOA 176(R12),X7
|
||||
MOVOA 192(R12),X8
|
||||
MOVOA 208(R12),X9
|
||||
MOVOA 224(R12),X10
|
||||
MOVOA 304(R12),X11
|
||||
MOVOA 112(R12),X12
|
||||
MOVOA 160(R12),X13
|
||||
MOVOA 240(R12),X14
|
||||
MOVOA 288(R12),X15
|
||||
MAINLOOP1:
|
||||
MOVOA X1,320(SP)
|
||||
MOVOA X2,336(SP)
|
||||
MOVOA X1,320(R12)
|
||||
MOVOA X2,336(R12)
|
||||
MOVOA X13,X1
|
||||
PADDL X12,X1
|
||||
MOVOA X1,X2
|
||||
@@ -191,8 +190,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X1,X12
|
||||
PSRLL $14,X2
|
||||
PXOR X2,X12
|
||||
MOVOA 320(SP),X1
|
||||
MOVOA X12,320(SP)
|
||||
MOVOA 320(R12),X1
|
||||
MOVOA X12,320(R12)
|
||||
MOVOA X9,X2
|
||||
PADDL X7,X2
|
||||
MOVOA X2,X12
|
||||
@@ -207,8 +206,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X2,X3
|
||||
PSRLL $25,X12
|
||||
PXOR X12,X3
|
||||
MOVOA 336(SP),X2
|
||||
MOVOA X0,336(SP)
|
||||
MOVOA 336(R12),X2
|
||||
MOVOA X0,336(R12)
|
||||
MOVOA X6,X0
|
||||
PADDL X2,X0
|
||||
MOVOA X0,X12
|
||||
@@ -251,8 +250,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X0,X1
|
||||
PSRLL $14,X12
|
||||
PXOR X12,X1
|
||||
MOVOA 320(SP),X0
|
||||
MOVOA X1,320(SP)
|
||||
MOVOA 320(R12),X0
|
||||
MOVOA X1,320(R12)
|
||||
MOVOA X4,X1
|
||||
PADDL X0,X1
|
||||
MOVOA X1,X12
|
||||
@@ -267,8 +266,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X1,X2
|
||||
PSRLL $14,X12
|
||||
PXOR X12,X2
|
||||
MOVOA 336(SP),X12
|
||||
MOVOA X2,336(SP)
|
||||
MOVOA 336(R12),X12
|
||||
MOVOA X2,336(R12)
|
||||
MOVOA X14,X1
|
||||
PADDL X12,X1
|
||||
MOVOA X1,X2
|
||||
@@ -311,8 +310,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X1,X0
|
||||
PSRLL $14,X2
|
||||
PXOR X2,X0
|
||||
MOVOA 320(SP),X1
|
||||
MOVOA X0,320(SP)
|
||||
MOVOA 320(R12),X1
|
||||
MOVOA X0,320(R12)
|
||||
MOVOA X8,X0
|
||||
PADDL X14,X0
|
||||
MOVOA X0,X2
|
||||
@@ -327,8 +326,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X0,X6
|
||||
PSRLL $25,X2
|
||||
PXOR X2,X6
|
||||
MOVOA 336(SP),X2
|
||||
MOVOA X12,336(SP)
|
||||
MOVOA 336(R12),X2
|
||||
MOVOA X12,336(R12)
|
||||
MOVOA X3,X0
|
||||
PADDL X2,X0
|
||||
MOVOA X0,X12
|
||||
@@ -378,14 +377,14 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X0,X2
|
||||
PSRLL $14,X12
|
||||
PXOR X12,X2
|
||||
MOVOA 320(SP),X12
|
||||
MOVOA 336(SP),X0
|
||||
MOVOA 320(R12),X12
|
||||
MOVOA 336(R12),X0
|
||||
SUBQ $2,DX
|
||||
JA MAINLOOP1
|
||||
PADDL 112(SP),X12
|
||||
PADDL 176(SP),X7
|
||||
PADDL 224(SP),X10
|
||||
PADDL 272(SP),X4
|
||||
PADDL 112(R12),X12
|
||||
PADDL 176(R12),X7
|
||||
PADDL 224(R12),X10
|
||||
PADDL 272(R12),X4
|
||||
MOVD X12,DX
|
||||
MOVD X7,CX
|
||||
MOVD X10,R8
|
||||
@@ -446,10 +445,10 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL CX,196(DI)
|
||||
MOVL R8,200(DI)
|
||||
MOVL R9,204(DI)
|
||||
PADDL 240(SP),X14
|
||||
PADDL 64(SP),X0
|
||||
PADDL 128(SP),X5
|
||||
PADDL 192(SP),X8
|
||||
PADDL 240(R12),X14
|
||||
PADDL 64(R12),X0
|
||||
PADDL 128(R12),X5
|
||||
PADDL 192(R12),X8
|
||||
MOVD X14,DX
|
||||
MOVD X0,CX
|
||||
MOVD X5,R8
|
||||
@@ -510,10 +509,10 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL CX,212(DI)
|
||||
MOVL R8,216(DI)
|
||||
MOVL R9,220(DI)
|
||||
PADDL 288(SP),X15
|
||||
PADDL 304(SP),X11
|
||||
PADDL 80(SP),X1
|
||||
PADDL 144(SP),X6
|
||||
PADDL 288(R12),X15
|
||||
PADDL 304(R12),X11
|
||||
PADDL 80(R12),X1
|
||||
PADDL 144(R12),X6
|
||||
MOVD X15,DX
|
||||
MOVD X11,CX
|
||||
MOVD X1,R8
|
||||
@@ -574,10 +573,10 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL CX,228(DI)
|
||||
MOVL R8,232(DI)
|
||||
MOVL R9,236(DI)
|
||||
PADDL 160(SP),X13
|
||||
PADDL 208(SP),X9
|
||||
PADDL 256(SP),X3
|
||||
PADDL 96(SP),X2
|
||||
PADDL 160(R12),X13
|
||||
PADDL 208(R12),X9
|
||||
PADDL 256(R12),X3
|
||||
PADDL 96(R12),X2
|
||||
MOVD X13,DX
|
||||
MOVD X9,CX
|
||||
MOVD X3,R8
|
||||
@@ -638,7 +637,7 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL CX,244(DI)
|
||||
MOVL R8,248(DI)
|
||||
MOVL R9,252(DI)
|
||||
MOVQ 352(SP),R9
|
||||
MOVQ 352(R12),R9
|
||||
SUBQ $256,R9
|
||||
ADDQ $256,SI
|
||||
ADDQ $256,DI
|
||||
@@ -650,17 +649,17 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
CMPQ R9,$64
|
||||
JAE NOCOPY
|
||||
MOVQ DI,DX
|
||||
LEAQ 360(SP),DI
|
||||
LEAQ 360(R12),DI
|
||||
MOVQ R9,CX
|
||||
REP; MOVSB
|
||||
LEAQ 360(SP),DI
|
||||
LEAQ 360(SP),SI
|
||||
LEAQ 360(R12),DI
|
||||
LEAQ 360(R12),SI
|
||||
NOCOPY:
|
||||
MOVQ R9,352(SP)
|
||||
MOVOA 48(SP),X0
|
||||
MOVOA 0(SP),X1
|
||||
MOVOA 16(SP),X2
|
||||
MOVOA 32(SP),X3
|
||||
MOVQ R9,352(R12)
|
||||
MOVOA 48(R12),X0
|
||||
MOVOA 0(R12),X1
|
||||
MOVOA 16(R12),X2
|
||||
MOVOA 32(R12),X3
|
||||
MOVOA X1,X4
|
||||
MOVQ $20,CX
|
||||
MAINLOOP2:
|
||||
@@ -791,10 +790,10 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PSHUFL $0X39,X3,X3
|
||||
PXOR X6,X0
|
||||
JA MAINLOOP2
|
||||
PADDL 48(SP),X0
|
||||
PADDL 0(SP),X1
|
||||
PADDL 16(SP),X2
|
||||
PADDL 32(SP),X3
|
||||
PADDL 48(R12),X0
|
||||
PADDL 0(R12),X1
|
||||
PADDL 16(R12),X2
|
||||
PADDL 32(R12),X3
|
||||
MOVD X0,CX
|
||||
MOVD X1,R8
|
||||
MOVD X2,R9
|
||||
@@ -855,16 +854,16 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL R8,44(DI)
|
||||
MOVL R9,28(DI)
|
||||
MOVL AX,12(DI)
|
||||
MOVQ 352(SP),R9
|
||||
MOVL 16(SP),CX
|
||||
MOVL 36 (SP),R8
|
||||
MOVQ 352(R12),R9
|
||||
MOVL 16(R12),CX
|
||||
MOVL 36 (R12),R8
|
||||
ADDQ $1,CX
|
||||
SHLQ $32,R8
|
||||
ADDQ R8,CX
|
||||
MOVQ CX,R8
|
||||
SHRQ $32,R8
|
||||
MOVL CX,16(SP)
|
||||
MOVL R8, 36 (SP)
|
||||
MOVL CX,16(R12)
|
||||
MOVL R8, 36 (R12)
|
||||
CMPQ R9,$64
|
||||
JA BYTESATLEAST65
|
||||
JAE BYTESATLEAST64
|
||||
@@ -874,7 +873,6 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
REP; MOVSB
|
||||
BYTESATLEAST64:
|
||||
DONE:
|
||||
MOVQ R12,SP
|
||||
RET
|
||||
BYTESATLEAST65:
|
||||
SUBQ $64,R9
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !amd64 appengine gccgo
|
||||
//go:build !amd64 || purego || !gc
|
||||
// +build !amd64 purego !gc
|
||||
|
||||
package salsa
|
||||
|
||||
|
||||
+2
-4
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package bpf implements marshaling and unmarshaling of programs for the
|
||||
Berkeley Packet Filter virtual machine, and provides a Go implementation
|
||||
of the virtual machine.
|
||||
@@ -21,7 +20,7 @@ access to kernel functions, and while conditional branches are
|
||||
allowed, they can only jump forwards, to guarantee that there are no
|
||||
infinite loops.
|
||||
|
||||
The virtual machine
|
||||
# The virtual machine
|
||||
|
||||
The BPF VM is an accumulator machine. Its main register, called
|
||||
register A, is an implicit source and destination in all arithmetic
|
||||
@@ -50,7 +49,7 @@ to extensions, which are essentially calls to kernel utility
|
||||
functions. Currently, the only extensions supported by this package
|
||||
are the Linux packet filter extensions.
|
||||
|
||||
Examples
|
||||
# Examples
|
||||
|
||||
This packet filter selects all ARP packets.
|
||||
|
||||
@@ -77,6 +76,5 @@ This packet filter captures a random 1% sample of traffic.
|
||||
// Ignore.
|
||||
bpf.RetConstant{Val: 0},
|
||||
})
|
||||
|
||||
*/
|
||||
package bpf // import "golang.org/x/net/bpf"
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd
|
||||
// +build aix darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package socket
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm mips mipsle 386
|
||||
//go:build (arm || mips || mipsle || 386 || ppc) && linux
|
||||
// +build arm mips mipsle 386 ppc
|
||||
// +build linux
|
||||
|
||||
package socket
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
|
||||
// +build arm64 amd64 loong64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
// +build linux
|
||||
|
||||
package socket
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64
|
||||
// +build solaris
|
||||
//go:build amd64 && solaris
|
||||
// +build amd64,solaris
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+14
-3
@@ -2,13 +2,24 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!zos
|
||||
|
||||
package socket
|
||||
|
||||
type cmsghdr struct{}
|
||||
func controlHeaderLen() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
const sizeofCmsghdr = 0
|
||||
func controlMessageLen(dataLen int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func controlMessageSpace(dataLen int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
type cmsghdr struct{}
|
||||
|
||||
func (h *cmsghdr) len() int { return 0 }
|
||||
func (h *cmsghdr) lvl() int { return 0 }
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin && go1.12
|
||||
// +build darwin,go1.12
|
||||
|
||||
// This exists solely so we can linkname in symbols from syscall.
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm mips mipsle 386
|
||||
//go:build (arm || mips || mipsle || 386 || ppc) && (darwin || dragonfly || freebsd || linux || netbsd || openbsd)
|
||||
// +build arm mips mipsle 386 ppc
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd
|
||||
|
||||
package socket
|
||||
|
||||
+3
-2
@@ -2,8 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd
|
||||
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos)
|
||||
// +build arm64 amd64 loong64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64
|
||||
// +build solaris
|
||||
//go:build amd64 && solaris
|
||||
// +build amd64,solaris
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !aix && !linux && !netbsd
|
||||
// +build !aix,!linux,!netbsd
|
||||
|
||||
package socket
|
||||
|
||||
+154
-16
@@ -2,29 +2,20 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || linux || netbsd
|
||||
// +build aix linux netbsd
|
||||
|
||||
package socket
|
||||
|
||||
import "net"
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type mmsghdrs []mmsghdr
|
||||
|
||||
func (hs mmsghdrs) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr) []byte) error {
|
||||
for i := range hs {
|
||||
vs := make([]iovec, len(ms[i].Buffers))
|
||||
var sa []byte
|
||||
if parseFn != nil {
|
||||
sa = make([]byte, sizeofSockaddrInet6)
|
||||
}
|
||||
if marshalFn != nil {
|
||||
sa = marshalFn(ms[i].Addr)
|
||||
}
|
||||
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
|
||||
for i := range hs {
|
||||
ms[i].N = int(hs[i].Len)
|
||||
@@ -40,3 +31,150 @@ func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mmsghdrsPacker packs Message-slices into mmsghdrs (re-)using pre-allocated buffers.
|
||||
type mmsghdrsPacker struct {
|
||||
// hs are the pre-allocated mmsghdrs.
|
||||
hs mmsghdrs
|
||||
// sockaddrs is the pre-allocated buffer for the Hdr.Name buffers.
|
||||
// We use one large buffer for all messages and slice it up.
|
||||
sockaddrs []byte
|
||||
// vs are the pre-allocated iovecs.
|
||||
// We allocate one large buffer for all messages and slice it up. This allows to reuse the buffer
|
||||
// if the number of buffers per message is distributed differently between calls.
|
||||
vs []iovec
|
||||
}
|
||||
|
||||
func (p *mmsghdrsPacker) prepare(ms []Message) {
|
||||
n := len(ms)
|
||||
if n <= cap(p.hs) {
|
||||
p.hs = p.hs[:n]
|
||||
} else {
|
||||
p.hs = make(mmsghdrs, n)
|
||||
}
|
||||
if n*sizeofSockaddrInet6 <= cap(p.sockaddrs) {
|
||||
p.sockaddrs = p.sockaddrs[:n*sizeofSockaddrInet6]
|
||||
} else {
|
||||
p.sockaddrs = make([]byte, n*sizeofSockaddrInet6)
|
||||
}
|
||||
|
||||
nb := 0
|
||||
for _, m := range ms {
|
||||
nb += len(m.Buffers)
|
||||
}
|
||||
if nb <= cap(p.vs) {
|
||||
p.vs = p.vs[:nb]
|
||||
} else {
|
||||
p.vs = make([]iovec, nb)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *mmsghdrsPacker) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr, []byte) int) mmsghdrs {
|
||||
p.prepare(ms)
|
||||
hs := p.hs
|
||||
vsRest := p.vs
|
||||
saRest := p.sockaddrs
|
||||
for i := range hs {
|
||||
nvs := len(ms[i].Buffers)
|
||||
vs := vsRest[:nvs]
|
||||
vsRest = vsRest[nvs:]
|
||||
|
||||
var sa []byte
|
||||
if parseFn != nil {
|
||||
sa = saRest[:sizeofSockaddrInet6]
|
||||
saRest = saRest[sizeofSockaddrInet6:]
|
||||
} else if marshalFn != nil {
|
||||
n := marshalFn(ms[i].Addr, saRest)
|
||||
if n > 0 {
|
||||
sa = saRest[:n]
|
||||
saRest = saRest[n:]
|
||||
}
|
||||
}
|
||||
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
|
||||
}
|
||||
return hs
|
||||
}
|
||||
|
||||
// syscaller is a helper to invoke recvmmsg and sendmmsg via the RawConn.Read/Write interface.
|
||||
// It is reusable, to amortize the overhead of allocating a closure for the function passed to
|
||||
// RawConn.Read/Write.
|
||||
type syscaller struct {
|
||||
n int
|
||||
operr error
|
||||
hs mmsghdrs
|
||||
flags int
|
||||
|
||||
boundRecvmmsgF func(uintptr) bool
|
||||
boundSendmmsgF func(uintptr) bool
|
||||
}
|
||||
|
||||
func (r *syscaller) init() {
|
||||
r.boundRecvmmsgF = r.recvmmsgF
|
||||
r.boundSendmmsgF = r.sendmmsgF
|
||||
}
|
||||
|
||||
func (r *syscaller) recvmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
|
||||
r.n = 0
|
||||
r.operr = nil
|
||||
r.hs = hs
|
||||
r.flags = flags
|
||||
if err := c.Read(r.boundRecvmmsgF); err != nil {
|
||||
return r.n, err
|
||||
}
|
||||
if r.operr != nil {
|
||||
return r.n, os.NewSyscallError("recvmmsg", r.operr)
|
||||
}
|
||||
return r.n, nil
|
||||
}
|
||||
|
||||
func (r *syscaller) recvmmsgF(s uintptr) bool {
|
||||
r.n, r.operr = recvmmsg(s, r.hs, r.flags)
|
||||
return ioComplete(r.flags, r.operr)
|
||||
}
|
||||
|
||||
func (r *syscaller) sendmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
|
||||
r.n = 0
|
||||
r.operr = nil
|
||||
r.hs = hs
|
||||
r.flags = flags
|
||||
if err := c.Write(r.boundSendmmsgF); err != nil {
|
||||
return r.n, err
|
||||
}
|
||||
if r.operr != nil {
|
||||
return r.n, os.NewSyscallError("sendmmsg", r.operr)
|
||||
}
|
||||
return r.n, nil
|
||||
}
|
||||
|
||||
func (r *syscaller) sendmmsgF(s uintptr) bool {
|
||||
r.n, r.operr = sendmmsg(s, r.hs, r.flags)
|
||||
return ioComplete(r.flags, r.operr)
|
||||
}
|
||||
|
||||
// mmsgTmps holds reusable temporary helpers for recvmmsg and sendmmsg.
|
||||
type mmsgTmps struct {
|
||||
packer mmsghdrsPacker
|
||||
syscaller syscaller
|
||||
}
|
||||
|
||||
var defaultMmsgTmpsPool = mmsgTmpsPool{
|
||||
p: sync.Pool{
|
||||
New: func() interface{} {
|
||||
tmps := new(mmsgTmps)
|
||||
tmps.syscaller.init()
|
||||
return tmps
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type mmsgTmpsPool struct {
|
||||
p sync.Pool
|
||||
}
|
||||
|
||||
func (p *mmsgTmpsPool) Get() *mmsgTmps {
|
||||
return p.p.Get().(*mmsgTmps)
|
||||
}
|
||||
|
||||
func (p *mmsgTmpsPool) Put(tmps *mmsgTmps) {
|
||||
p.p.Put(tmps)
|
||||
}
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd
|
||||
// +build aix darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package socket
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || netbsd
|
||||
// +build aix darwin dragonfly freebsd netbsd
|
||||
|
||||
package socket
|
||||
|
||||
+3
@@ -17,6 +17,9 @@ func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
|
||||
if sa != nil {
|
||||
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
|
||||
h.Namelen = uint32(len(sa))
|
||||
} else {
|
||||
h.Name = nil
|
||||
h.Namelen = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm mips mipsle 386
|
||||
//go:build (arm || mips || mipsle || 386 || ppc) && linux
|
||||
// +build arm mips mipsle 386 ppc
|
||||
// +build linux
|
||||
|
||||
package socket
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
|
||||
// +build arm64 amd64 loong64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
// +build linux
|
||||
|
||||
package socket
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64
|
||||
// +build solaris
|
||||
//go:build amd64 && solaris
|
||||
// +build amd64,solaris
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !race
|
||||
// +build !race
|
||||
|
||||
package socket
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build race
|
||||
// +build race
|
||||
|
||||
package socket
|
||||
|
||||
+30
-3
@@ -17,18 +17,45 @@ type Conn struct {
|
||||
c syscall.RawConn
|
||||
}
|
||||
|
||||
// tcpConn is an interface implemented by net.TCPConn.
|
||||
// It can be used for interface assertions to check if a net.Conn is a TCP connection.
|
||||
type tcpConn interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
SetLinger(int) error
|
||||
}
|
||||
|
||||
var _ tcpConn = (*net.TCPConn)(nil)
|
||||
|
||||
// udpConn is an interface implemented by net.UDPConn.
|
||||
// It can be used for interface assertions to check if a net.Conn is a UDP connection.
|
||||
type udpConn interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
|
||||
}
|
||||
|
||||
var _ udpConn = (*net.UDPConn)(nil)
|
||||
|
||||
// ipConn is an interface implemented by net.IPConn.
|
||||
// It can be used for interface assertions to check if a net.Conn is an IP connection.
|
||||
type ipConn interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *net.IPAddr, err error)
|
||||
}
|
||||
|
||||
var _ ipConn = (*net.IPConn)(nil)
|
||||
|
||||
// NewConn returns a new raw connection.
|
||||
func NewConn(c net.Conn) (*Conn, error) {
|
||||
var err error
|
||||
var cc Conn
|
||||
switch c := c.(type) {
|
||||
case *net.TCPConn:
|
||||
case tcpConn:
|
||||
cc.network = "tcp"
|
||||
cc.c, err = c.SyscallConn()
|
||||
case *net.UDPConn:
|
||||
case udpConn:
|
||||
cc.network = "udp"
|
||||
cc.c, err = c.SyscallConn()
|
||||
case *net.IPConn:
|
||||
case ipConn:
|
||||
cc.network = "ip"
|
||||
cc.c, err = c.SyscallConn()
|
||||
default:
|
||||
|
||||
+12
-37
@@ -2,43 +2,30 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
|
||||
for i := range ms {
|
||||
ms[i].raceWrite()
|
||||
}
|
||||
hs := make(mmsghdrs, len(ms))
|
||||
tmps := defaultMmsgTmpsPool.Get()
|
||||
defer defaultMmsgTmpsPool.Put(tmps)
|
||||
var parseFn func([]byte, string) (net.Addr, error)
|
||||
if c.network != "tcp" {
|
||||
parseFn = parseInetAddr
|
||||
}
|
||||
if err := hs.pack(ms, parseFn, nil); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var operr error
|
||||
var n int
|
||||
fn := func(s uintptr) bool {
|
||||
n, operr = recvmmsg(s, hs, flags)
|
||||
if operr == syscall.EAGAIN {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
if err := c.c.Read(fn); err != nil {
|
||||
hs := tmps.packer.pack(ms, parseFn, nil)
|
||||
n, err := tmps.syscaller.recvmmsg(c.c, hs, flags)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if operr != nil {
|
||||
return n, os.NewSyscallError("recvmmsg", operr)
|
||||
}
|
||||
if err := hs[:n].unpack(ms[:n], parseFn, c.network); err != nil {
|
||||
return n, err
|
||||
}
|
||||
@@ -49,29 +36,17 @@ func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
|
||||
for i := range ms {
|
||||
ms[i].raceRead()
|
||||
}
|
||||
hs := make(mmsghdrs, len(ms))
|
||||
var marshalFn func(net.Addr) []byte
|
||||
tmps := defaultMmsgTmpsPool.Get()
|
||||
defer defaultMmsgTmpsPool.Put(tmps)
|
||||
var marshalFn func(net.Addr, []byte) int
|
||||
if c.network != "tcp" {
|
||||
marshalFn = marshalInetAddr
|
||||
}
|
||||
if err := hs.pack(ms, nil, marshalFn); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var operr error
|
||||
var n int
|
||||
fn := func(s uintptr) bool {
|
||||
n, operr = sendmmsg(s, hs, flags)
|
||||
if operr == syscall.EAGAIN {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
if err := c.c.Write(fn); err != nil {
|
||||
hs := tmps.packer.pack(ms, nil, marshalFn)
|
||||
n, err := tmps.syscaller.sendmmsg(c.c, hs, flags)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if operr != nil {
|
||||
return n, os.NewSyscallError("sendmmsg", operr)
|
||||
}
|
||||
if err := hs[:n].unpack(ms[:n], nil, ""); err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
+7
-11
@@ -2,13 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows zos
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (c *Conn) recvMsg(m *Message, flags int) error {
|
||||
@@ -24,10 +24,7 @@ func (c *Conn) recvMsg(m *Message, flags int) error {
|
||||
var n int
|
||||
fn := func(s uintptr) bool {
|
||||
n, operr = recvmsg(s, &h, flags)
|
||||
if operr == syscall.EAGAIN {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return ioComplete(flags, operr)
|
||||
}
|
||||
if err := c.c.Read(fn); err != nil {
|
||||
return err
|
||||
@@ -54,17 +51,16 @@ func (c *Conn) sendMsg(m *Message, flags int) error {
|
||||
vs := make([]iovec, len(m.Buffers))
|
||||
var sa []byte
|
||||
if m.Addr != nil {
|
||||
sa = marshalInetAddr(m.Addr)
|
||||
var a [sizeofSockaddrInet6]byte
|
||||
n := marshalInetAddr(m.Addr, a[:])
|
||||
sa = a[:n]
|
||||
}
|
||||
h.pack(vs, m.Buffers, m.OOB, sa)
|
||||
var operr error
|
||||
var n int
|
||||
fn := func(s uintptr) bool {
|
||||
n, operr = sendmsg(s, &h, flags)
|
||||
if operr == syscall.EAGAIN {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return ioComplete(flags, operr)
|
||||
}
|
||||
if err := c.c.Write(fn); err != nil {
|
||||
return err
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package socket
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
|
||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows,!zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+1
-9
@@ -90,17 +90,9 @@ func (o *Option) SetInt(c *Conn, v int) error {
|
||||
return o.set(c, b)
|
||||
}
|
||||
|
||||
func controlHeaderLen() int {
|
||||
return roundup(sizeofCmsghdr)
|
||||
}
|
||||
|
||||
func controlMessageLen(dataLen int) int {
|
||||
return roundup(sizeofCmsghdr) + dataLen
|
||||
}
|
||||
|
||||
// ControlMessageSpace returns the whole length of control message.
|
||||
func ControlMessageSpace(dataLen int) int {
|
||||
return roundup(sizeofCmsghdr) + roundup(dataLen)
|
||||
return controlMessageSpace(dataLen)
|
||||
}
|
||||
|
||||
// A ControlMessage represents the head message in a stream of control
|
||||
|
||||
+2
-12
@@ -9,13 +9,8 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
// NativeEndian is the machine native endian implementation of
|
||||
// ByteOrder.
|
||||
NativeEndian binary.ByteOrder
|
||||
|
||||
kernelAlign int
|
||||
)
|
||||
// NativeEndian is the machine native endian implementation of ByteOrder.
|
||||
var NativeEndian binary.ByteOrder
|
||||
|
||||
func init() {
|
||||
i := uint32(1)
|
||||
@@ -25,9 +20,4 @@ func init() {
|
||||
} else {
|
||||
NativeEndian = binary.BigEndian
|
||||
}
|
||||
kernelAlign = probeProtocolStack()
|
||||
}
|
||||
|
||||
func roundup(l int) int {
|
||||
return (l + kernelAlign - 1) &^ (kernelAlign - 1)
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd openbsd
|
||||
//go:build aix || darwin || dragonfly || freebsd || openbsd || solaris
|
||||
// +build aix darwin dragonfly freebsd openbsd solaris
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright 2017 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 aix freebsd netbsd openbsd
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func probeProtocolStack() int {
|
||||
if (runtime.GOOS == "netbsd" || runtime.GOOS == "openbsd") && runtime.GOARCH == "arm" {
|
||||
return 8
|
||||
}
|
||||
if runtime.GOOS == "aix" {
|
||||
return 1
|
||||
}
|
||||
var p uintptr
|
||||
return int(unsafe.Sizeof(p))
|
||||
}
|
||||
+5
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package socket
|
||||
|
||||
@@ -14,4 +15,7 @@ const (
|
||||
sysAF_INET6 = unix.AF_INET6
|
||||
|
||||
sysSOCK_RAW = unix.SOCK_RAW
|
||||
|
||||
sizeofSockaddrInet4 = unix.SizeofSockaddrInet4
|
||||
sizeofSockaddrInet6 = unix.SizeofSockaddrInet6
|
||||
)
|
||||
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
// Copyright 2017 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 socket
|
||||
|
||||
func probeProtocolStack() int { return 4 }
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
// Copyright 2017 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 socket
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// See version list in https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/param.h
|
||||
var (
|
||||
osreldateOnce sync.Once
|
||||
osreldate uint32
|
||||
)
|
||||
|
||||
// First __DragonFly_version after September 2019 ABI changes
|
||||
// http://lists.dragonflybsd.org/pipermail/users/2019-September/358280.html
|
||||
const _dragonflyABIChangeVersion = 500705
|
||||
|
||||
func probeProtocolStack() int {
|
||||
osreldateOnce.Do(func() { osreldate, _ = syscall.SysctlUint32("kern.osreldate") })
|
||||
var p uintptr
|
||||
if int(unsafe.Sizeof(p)) == 8 && osreldate >= _dragonflyABIChangeVersion {
|
||||
return int(unsafe.Sizeof(p))
|
||||
}
|
||||
// 64-bit Dragonfly before the September 2019 ABI changes still requires
|
||||
// 32-bit aligned access to network subsystem.
|
||||
return 4
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user