mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-07-10 22:23:47 +02:00
+7
-7
@@ -26,10 +26,10 @@ require (
|
||||
github.com/wneessen/go-mail v0.7.2
|
||||
github.com/yeqown/go-qrcode/v2 v2.2.4
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.43.0
|
||||
golang.org/x/mod v0.29.0
|
||||
golang.org/x/net v0.46.0
|
||||
golang.org/x/sync v0.18.0
|
||||
golang.org/x/crypto v0.49.0
|
||||
golang.org/x/mod v0.33.0
|
||||
golang.org/x/net v0.51.0
|
||||
golang.org/x/sync v0.20.0
|
||||
golang.org/x/time v0.14.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gorm.io/driver/sqlite v1.6.0
|
||||
@@ -106,8 +106,8 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/tools v0.38.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
golang.org/x/tools v0.42.0 // indirect
|
||||
google.golang.org/protobuf v1.36.7 // indirect
|
||||
)
|
||||
|
||||
@@ -251,6 +251,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
@@ -258,6 +260,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
@@ -266,10 +270,14 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -283,6 +291,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
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/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -293,6 +303,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -301,6 +313,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
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=
|
||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||
|
||||
+11
-7
@@ -6,7 +6,7 @@
|
||||
// Argon2 was selected as the winner of the Password Hashing Competition and can
|
||||
// be used to derive cryptographic keys from passwords.
|
||||
//
|
||||
// For a detailed specification of Argon2 see [1].
|
||||
// For a detailed specification of Argon2 see [argon2-specs.pdf].
|
||||
//
|
||||
// If you aren't sure which function you need, use Argon2id (IDKey) and
|
||||
// the parameter recommendations for your scenario.
|
||||
@@ -17,7 +17,7 @@
|
||||
// It uses data-independent memory access, which is preferred for password
|
||||
// hashing and password-based key derivation. Argon2i requires more passes over
|
||||
// memory than Argon2id to protect from trade-off attacks. The recommended
|
||||
// parameters (taken from [2]) for non-interactive operations are time=3 and to
|
||||
// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive operations are time=3 and to
|
||||
// use the maximum available memory.
|
||||
//
|
||||
// # Argon2id
|
||||
@@ -27,11 +27,11 @@
|
||||
// half of the first iteration over the memory and data-dependent memory access
|
||||
// for the rest. Argon2id is side-channel resistant and provides better brute-
|
||||
// force cost savings due to time-memory tradeoffs than Argon2i. The recommended
|
||||
// parameters for non-interactive operations (taken from [2]) are time=1 and to
|
||||
// parameters for non-interactive operations (taken from [RFC 9106 Section 7.3]) are time=1 and to
|
||||
// use the maximum available memory.
|
||||
//
|
||||
// [1] https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
|
||||
// [2] https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03#section-9.3
|
||||
// [argon2-specs.pdf]: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
|
||||
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
|
||||
package argon2
|
||||
|
||||
import (
|
||||
@@ -59,7 +59,7 @@ const (
|
||||
//
|
||||
// key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32)
|
||||
//
|
||||
// The draft RFC recommends[2] time=3, and memory=32*1024 is a sensible number.
|
||||
// [RFC 9106 Section 7.3] recommends time=3, and memory=32*1024 as a sensible number.
|
||||
// If using that amount of memory (32 MB) is not possible in some contexts then
|
||||
// the time parameter can be increased to compensate.
|
||||
//
|
||||
@@ -69,6 +69,8 @@ const (
|
||||
// adjusted to the number of available CPUs. The cost parameters should be
|
||||
// increased as memory latency and CPU parallelism increases. Remember to get a
|
||||
// good random salt.
|
||||
//
|
||||
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
|
||||
func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
|
||||
return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
|
||||
}
|
||||
@@ -83,7 +85,7 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3
|
||||
//
|
||||
// key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32)
|
||||
//
|
||||
// The draft RFC recommends[2] time=1, and memory=64*1024 is a sensible number.
|
||||
// [RFC 9106 Section 7.3] recommends time=1, and memory=64*1024 as a sensible number.
|
||||
// If using that amount of memory (64 MB) is not possible in some contexts then
|
||||
// the time parameter can be increased to compensate.
|
||||
//
|
||||
@@ -93,6 +95,8 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3
|
||||
// adjusted to the numbers of available CPUs. The cost parameters should be
|
||||
// increased as memory latency and CPU parallelism increases. Remember to get a
|
||||
// good random salt.
|
||||
//
|
||||
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
|
||||
func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
|
||||
return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen)
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bcrypt
|
||||
|
||||
import "encoding/base64"
|
||||
|
||||
const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
var bcEncoding = base64.NewEncoding(alphabet)
|
||||
|
||||
func base64Encode(src []byte) []byte {
|
||||
n := bcEncoding.EncodedLen(len(src))
|
||||
dst := make([]byte, n)
|
||||
bcEncoding.Encode(dst, src)
|
||||
for dst[n-1] == '=' {
|
||||
n--
|
||||
}
|
||||
return dst[:n]
|
||||
}
|
||||
|
||||
func base64Decode(src []byte) ([]byte, error) {
|
||||
numOfEquals := 4 - (len(src) % 4)
|
||||
for i := 0; i < numOfEquals; i++ {
|
||||
src = append(src, '=')
|
||||
}
|
||||
|
||||
dst := make([]byte, bcEncoding.DecodedLen(len(src)))
|
||||
n, err := bcEncoding.Decode(dst, src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dst[:n], nil
|
||||
}
|
||||
+304
@@ -0,0 +1,304 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
|
||||
// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
|
||||
package bcrypt
|
||||
|
||||
// The code is a port of Provos and Mazières's C implementation.
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/crypto/blowfish"
|
||||
)
|
||||
|
||||
const (
|
||||
MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword
|
||||
MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword
|
||||
DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword
|
||||
)
|
||||
|
||||
// The error returned from CompareHashAndPassword when a password and hash do
|
||||
// not match.
|
||||
var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password")
|
||||
|
||||
// The error returned from CompareHashAndPassword when a hash is too short to
|
||||
// be a bcrypt hash.
|
||||
var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password")
|
||||
|
||||
// The error returned from CompareHashAndPassword when a hash was created with
|
||||
// a bcrypt algorithm newer than this implementation.
|
||||
type HashVersionTooNewError byte
|
||||
|
||||
func (hv HashVersionTooNewError) Error() string {
|
||||
return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion)
|
||||
}
|
||||
|
||||
// The error returned from CompareHashAndPassword when a hash starts with something other than '$'
|
||||
type InvalidHashPrefixError byte
|
||||
|
||||
func (ih InvalidHashPrefixError) Error() string {
|
||||
return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih))
|
||||
}
|
||||
|
||||
type InvalidCostError int
|
||||
|
||||
func (ic InvalidCostError) Error() string {
|
||||
return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed inclusive range %d..%d", int(ic), MinCost, MaxCost)
|
||||
}
|
||||
|
||||
const (
|
||||
majorVersion = '2'
|
||||
minorVersion = 'a'
|
||||
maxSaltSize = 16
|
||||
maxCryptedHashSize = 23
|
||||
encodedSaltSize = 22
|
||||
encodedHashSize = 31
|
||||
minHashSize = 59
|
||||
)
|
||||
|
||||
// magicCipherData is an IV for the 64 Blowfish encryption calls in
|
||||
// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes.
|
||||
var magicCipherData = []byte{
|
||||
0x4f, 0x72, 0x70, 0x68,
|
||||
0x65, 0x61, 0x6e, 0x42,
|
||||
0x65, 0x68, 0x6f, 0x6c,
|
||||
0x64, 0x65, 0x72, 0x53,
|
||||
0x63, 0x72, 0x79, 0x44,
|
||||
0x6f, 0x75, 0x62, 0x74,
|
||||
}
|
||||
|
||||
type hashed struct {
|
||||
hash []byte
|
||||
salt []byte
|
||||
cost int // allowed range is MinCost to MaxCost
|
||||
major byte
|
||||
minor byte
|
||||
}
|
||||
|
||||
// ErrPasswordTooLong is returned when the password passed to
|
||||
// GenerateFromPassword is too long (i.e. > 72 bytes).
|
||||
var ErrPasswordTooLong = errors.New("bcrypt: password length exceeds 72 bytes")
|
||||
|
||||
// GenerateFromPassword returns the bcrypt hash of the password at the given
|
||||
// cost. If the cost given is less than MinCost, the cost will be set to
|
||||
// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package,
|
||||
// to compare the returned hashed password with its cleartext version.
|
||||
// GenerateFromPassword does not accept passwords longer than 72 bytes, which
|
||||
// is the longest password bcrypt will operate on.
|
||||
func GenerateFromPassword(password []byte, cost int) ([]byte, error) {
|
||||
if len(password) > 72 {
|
||||
return nil, ErrPasswordTooLong
|
||||
}
|
||||
p, err := newFromPassword(password, cost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.Hash(), nil
|
||||
}
|
||||
|
||||
// CompareHashAndPassword compares a bcrypt hashed password with its possible
|
||||
// plaintext equivalent. Returns nil on success, or an error on failure.
|
||||
func CompareHashAndPassword(hashedPassword, password []byte) error {
|
||||
p, err := newFromHash(hashedPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
otherHash, err := bcrypt(password, p.cost, p.salt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor}
|
||||
if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrMismatchedHashAndPassword
|
||||
}
|
||||
|
||||
// Cost returns the hashing cost used to create the given hashed
|
||||
// password. When, in the future, the hashing cost of a password system needs
|
||||
// to be increased in order to adjust for greater computational power, this
|
||||
// function allows one to establish which passwords need to be updated.
|
||||
func Cost(hashedPassword []byte) (int, error) {
|
||||
p, err := newFromHash(hashedPassword)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return p.cost, nil
|
||||
}
|
||||
|
||||
func newFromPassword(password []byte, cost int) (*hashed, error) {
|
||||
if cost < MinCost {
|
||||
cost = DefaultCost
|
||||
}
|
||||
p := new(hashed)
|
||||
p.major = majorVersion
|
||||
p.minor = minorVersion
|
||||
|
||||
err := checkCost(cost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.cost = cost
|
||||
|
||||
unencodedSalt := make([]byte, maxSaltSize)
|
||||
_, err = io.ReadFull(rand.Reader, unencodedSalt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.salt = base64Encode(unencodedSalt)
|
||||
hash, err := bcrypt(password, p.cost, p.salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.hash = hash
|
||||
return p, err
|
||||
}
|
||||
|
||||
func newFromHash(hashedSecret []byte) (*hashed, error) {
|
||||
if len(hashedSecret) < minHashSize {
|
||||
return nil, ErrHashTooShort
|
||||
}
|
||||
p := new(hashed)
|
||||
n, err := p.decodeVersion(hashedSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hashedSecret = hashedSecret[n:]
|
||||
n, err = p.decodeCost(hashedSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hashedSecret = hashedSecret[n:]
|
||||
|
||||
// The "+2" is here because we'll have to append at most 2 '=' to the salt
|
||||
// when base64 decoding it in expensiveBlowfishSetup().
|
||||
p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2)
|
||||
copy(p.salt, hashedSecret[:encodedSaltSize])
|
||||
|
||||
hashedSecret = hashedSecret[encodedSaltSize:]
|
||||
p.hash = make([]byte, len(hashedSecret))
|
||||
copy(p.hash, hashedSecret)
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
|
||||
cipherData := make([]byte, len(magicCipherData))
|
||||
copy(cipherData, magicCipherData)
|
||||
|
||||
c, err := expensiveBlowfishSetup(password, uint32(cost), salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < 24; i += 8 {
|
||||
for j := 0; j < 64; j++ {
|
||||
c.Encrypt(cipherData[i:i+8], cipherData[i:i+8])
|
||||
}
|
||||
}
|
||||
|
||||
// Bug compatibility with C bcrypt implementations. We only encode 23 of
|
||||
// the 24 bytes encrypted.
|
||||
hsh := base64Encode(cipherData[:maxCryptedHashSize])
|
||||
return hsh, nil
|
||||
}
|
||||
|
||||
func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
|
||||
csalt, err := base64Decode(salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Bug compatibility with C bcrypt implementations. They use the trailing
|
||||
// NULL in the key string during expansion.
|
||||
// We copy the key to prevent changing the underlying array.
|
||||
ckey := append(key[:len(key):len(key)], 0)
|
||||
|
||||
c, err := blowfish.NewSaltedCipher(ckey, csalt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var i, rounds uint64
|
||||
rounds = 1 << cost
|
||||
for i = 0; i < rounds; i++ {
|
||||
blowfish.ExpandKey(ckey, c)
|
||||
blowfish.ExpandKey(csalt, c)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (p *hashed) Hash() []byte {
|
||||
arr := make([]byte, 60)
|
||||
arr[0] = '$'
|
||||
arr[1] = p.major
|
||||
n := 2
|
||||
if p.minor != 0 {
|
||||
arr[2] = p.minor
|
||||
n = 3
|
||||
}
|
||||
arr[n] = '$'
|
||||
n++
|
||||
copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost)))
|
||||
n += 2
|
||||
arr[n] = '$'
|
||||
n++
|
||||
copy(arr[n:], p.salt)
|
||||
n += encodedSaltSize
|
||||
copy(arr[n:], p.hash)
|
||||
n += encodedHashSize
|
||||
return arr[:n]
|
||||
}
|
||||
|
||||
func (p *hashed) decodeVersion(sbytes []byte) (int, error) {
|
||||
if sbytes[0] != '$' {
|
||||
return -1, InvalidHashPrefixError(sbytes[0])
|
||||
}
|
||||
if sbytes[1] > majorVersion {
|
||||
return -1, HashVersionTooNewError(sbytes[1])
|
||||
}
|
||||
p.major = sbytes[1]
|
||||
n := 3
|
||||
if sbytes[2] != '$' {
|
||||
p.minor = sbytes[2]
|
||||
n++
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// sbytes should begin where decodeVersion left off.
|
||||
func (p *hashed) decodeCost(sbytes []byte) (int, error) {
|
||||
cost, err := strconv.Atoi(string(sbytes[0:2]))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
err = checkCost(cost)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
p.cost = cost
|
||||
return 3, nil
|
||||
}
|
||||
|
||||
func (p *hashed) String() string {
|
||||
return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor)
|
||||
}
|
||||
|
||||
func checkCost(cost int) error {
|
||||
if cost < MinCost || cost > MaxCost {
|
||||
return InvalidCostError(cost)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
// Copyright 2010 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 blowfish
|
||||
|
||||
// getNextWord returns the next big-endian uint32 value from the byte slice
|
||||
// at the given position in a circular manner, updating the position.
|
||||
func getNextWord(b []byte, pos *int) uint32 {
|
||||
var w uint32
|
||||
j := *pos
|
||||
for i := 0; i < 4; i++ {
|
||||
w = w<<8 | uint32(b[j])
|
||||
j++
|
||||
if j >= len(b) {
|
||||
j = 0
|
||||
}
|
||||
}
|
||||
*pos = j
|
||||
return w
|
||||
}
|
||||
|
||||
// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
|
||||
// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
|
||||
// pi and substitution tables for calls to Encrypt. This is used, primarily,
|
||||
// by the bcrypt package to reuse the Blowfish key schedule during its
|
||||
// set up. It's unlikely that you need to use this directly.
|
||||
func ExpandKey(key []byte, c *Cipher) {
|
||||
j := 0
|
||||
for i := 0; i < 18; i++ {
|
||||
// Using inlined getNextWord for performance.
|
||||
var d uint32
|
||||
for k := 0; k < 4; k++ {
|
||||
d = d<<8 | uint32(key[j])
|
||||
j++
|
||||
if j >= len(key) {
|
||||
j = 0
|
||||
}
|
||||
}
|
||||
c.p[i] ^= d
|
||||
}
|
||||
|
||||
var l, r uint32
|
||||
for i := 0; i < 18; i += 2 {
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.p[i], c.p[i+1] = l, r
|
||||
}
|
||||
|
||||
for i := 0; i < 256; i += 2 {
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.s0[i], c.s0[i+1] = l, r
|
||||
}
|
||||
for i := 0; i < 256; i += 2 {
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.s1[i], c.s1[i+1] = l, r
|
||||
}
|
||||
for i := 0; i < 256; i += 2 {
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.s2[i], c.s2[i+1] = l, r
|
||||
}
|
||||
for i := 0; i < 256; i += 2 {
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.s3[i], c.s3[i+1] = l, r
|
||||
}
|
||||
}
|
||||
|
||||
// This is similar to ExpandKey, but folds the salt during the key
|
||||
// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
|
||||
// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
|
||||
// and specializing it here is useful.
|
||||
func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
|
||||
j := 0
|
||||
for i := 0; i < 18; i++ {
|
||||
c.p[i] ^= getNextWord(key, &j)
|
||||
}
|
||||
|
||||
j = 0
|
||||
var l, r uint32
|
||||
for i := 0; i < 18; i += 2 {
|
||||
l ^= getNextWord(salt, &j)
|
||||
r ^= getNextWord(salt, &j)
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.p[i], c.p[i+1] = l, r
|
||||
}
|
||||
|
||||
for i := 0; i < 256; i += 2 {
|
||||
l ^= getNextWord(salt, &j)
|
||||
r ^= getNextWord(salt, &j)
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.s0[i], c.s0[i+1] = l, r
|
||||
}
|
||||
|
||||
for i := 0; i < 256; i += 2 {
|
||||
l ^= getNextWord(salt, &j)
|
||||
r ^= getNextWord(salt, &j)
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.s1[i], c.s1[i+1] = l, r
|
||||
}
|
||||
|
||||
for i := 0; i < 256; i += 2 {
|
||||
l ^= getNextWord(salt, &j)
|
||||
r ^= getNextWord(salt, &j)
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.s2[i], c.s2[i+1] = l, r
|
||||
}
|
||||
|
||||
for i := 0; i < 256; i += 2 {
|
||||
l ^= getNextWord(salt, &j)
|
||||
r ^= getNextWord(salt, &j)
|
||||
l, r = encryptBlock(l, r, c)
|
||||
c.s3[i], c.s3[i+1] = l, r
|
||||
}
|
||||
}
|
||||
|
||||
func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
|
||||
xl, xr := l, r
|
||||
xl ^= c.p[0]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
|
||||
xr ^= c.p[17]
|
||||
return xr, xl
|
||||
}
|
||||
|
||||
func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
|
||||
xl, xr := l, r
|
||||
xl ^= c.p[17]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
|
||||
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
|
||||
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
|
||||
xr ^= c.p[0]
|
||||
return xr, xl
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
// Copyright 2010 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 blowfish implements Bruce Schneier's Blowfish encryption algorithm.
|
||||
//
|
||||
// Blowfish is a legacy cipher and its short block size makes it vulnerable to
|
||||
// birthday bound attacks (see https://sweet32.info). It should only be used
|
||||
// where compatibility with legacy systems, not security, is the goal.
|
||||
//
|
||||
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
|
||||
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
|
||||
// golang.org/x/crypto/chacha20poly1305).
|
||||
package blowfish
|
||||
|
||||
// The code is a port of Bruce Schneier's C implementation.
|
||||
// See https://www.schneier.com/blowfish.html.
|
||||
|
||||
import "strconv"
|
||||
|
||||
// The Blowfish block size in bytes.
|
||||
const BlockSize = 8
|
||||
|
||||
// A Cipher is an instance of Blowfish encryption using a particular key.
|
||||
type Cipher struct {
|
||||
p [18]uint32
|
||||
s0, s1, s2, s3 [256]uint32
|
||||
}
|
||||
|
||||
type KeySizeError int
|
||||
|
||||
func (k KeySizeError) Error() string {
|
||||
return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
|
||||
}
|
||||
|
||||
// NewCipher creates and returns a Cipher.
|
||||
// The key argument should be the Blowfish key, from 1 to 56 bytes.
|
||||
func NewCipher(key []byte) (*Cipher, error) {
|
||||
var result Cipher
|
||||
if k := len(key); k < 1 || k > 56 {
|
||||
return nil, KeySizeError(k)
|
||||
}
|
||||
initCipher(&result)
|
||||
ExpandKey(key, &result)
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
|
||||
// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
|
||||
// sufficient and desirable. For bcrypt compatibility, the key can be over 56
|
||||
// bytes.
|
||||
func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
|
||||
if len(salt) == 0 {
|
||||
return NewCipher(key)
|
||||
}
|
||||
var result Cipher
|
||||
if k := len(key); k < 1 {
|
||||
return nil, KeySizeError(k)
|
||||
}
|
||||
initCipher(&result)
|
||||
expandKeyWithSalt(key, salt, &result)
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// BlockSize returns the Blowfish block size, 8 bytes.
|
||||
// It is necessary to satisfy the Block interface in the
|
||||
// package "crypto/cipher".
|
||||
func (c *Cipher) BlockSize() int { return BlockSize }
|
||||
|
||||
// Encrypt encrypts the 8-byte buffer src using the key k
|
||||
// and stores the result in dst.
|
||||
// Note that for amounts of data larger than a block,
|
||||
// it is not safe to just call Encrypt on successive blocks;
|
||||
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
|
||||
func (c *Cipher) Encrypt(dst, src []byte) {
|
||||
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
|
||||
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
|
||||
l, r = encryptBlock(l, r, c)
|
||||
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
|
||||
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
|
||||
}
|
||||
|
||||
// Decrypt decrypts the 8-byte buffer src using the key k
|
||||
// and stores the result in dst.
|
||||
func (c *Cipher) Decrypt(dst, src []byte) {
|
||||
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
|
||||
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
|
||||
l, r = decryptBlock(l, r, c)
|
||||
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
|
||||
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
|
||||
}
|
||||
|
||||
func initCipher(c *Cipher) {
|
||||
copy(c.p[0:], p[0:])
|
||||
copy(c.s0[0:], s0[0:])
|
||||
copy(c.s1[0:], s1[0:])
|
||||
copy(c.s2[0:], s2[0:])
|
||||
copy(c.s3[0:], s3[0:])
|
||||
}
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
// The startup permutation array and substitution boxes.
|
||||
// They are the hexadecimal digits of PI; see:
|
||||
// https://www.schneier.com/code/constants.txt.
|
||||
|
||||
package blowfish
|
||||
|
||||
var s0 = [256]uint32{
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
|
||||
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
|
||||
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
|
||||
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
|
||||
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
|
||||
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
|
||||
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
|
||||
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
|
||||
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
|
||||
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
|
||||
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
|
||||
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
|
||||
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
|
||||
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
|
||||
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
|
||||
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
|
||||
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
|
||||
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
|
||||
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
|
||||
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
|
||||
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
|
||||
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
|
||||
}
|
||||
|
||||
var s1 = [256]uint32{
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
|
||||
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
|
||||
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
|
||||
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
|
||||
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
|
||||
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
|
||||
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
|
||||
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
|
||||
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
|
||||
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
|
||||
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
|
||||
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
|
||||
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
|
||||
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
|
||||
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
|
||||
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
|
||||
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
|
||||
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
|
||||
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
|
||||
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
|
||||
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
|
||||
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
|
||||
}
|
||||
|
||||
var s2 = [256]uint32{
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
|
||||
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
|
||||
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
|
||||
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
|
||||
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
|
||||
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
|
||||
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
|
||||
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
|
||||
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
|
||||
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
|
||||
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
|
||||
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
|
||||
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
|
||||
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
|
||||
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
|
||||
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
|
||||
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
|
||||
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
|
||||
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
|
||||
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
|
||||
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
|
||||
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
|
||||
}
|
||||
|
||||
var s3 = [256]uint32{
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
|
||||
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
|
||||
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
|
||||
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
|
||||
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
|
||||
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
|
||||
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
|
||||
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
|
||||
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
|
||||
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
|
||||
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
|
||||
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
|
||||
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
|
||||
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
|
||||
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
|
||||
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
|
||||
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
|
||||
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
|
||||
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
|
||||
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
|
||||
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
|
||||
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
|
||||
}
|
||||
|
||||
var p = [18]uint32{
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
|
||||
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
|
||||
}
|
||||
+1
-1
@@ -29,7 +29,7 @@ loop:
|
||||
MOVD $NUM_ROUNDS, R21
|
||||
VLD1 (R11), [V30.S4, V31.S4]
|
||||
|
||||
// load contants
|
||||
// load constants
|
||||
// VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4]
|
||||
WORD $0x4D60E940
|
||||
|
||||
|
||||
+3
@@ -38,6 +38,9 @@ type chacha20poly1305 struct {
|
||||
|
||||
// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
|
||||
func New(key []byte) (cipher.AEAD, error) {
|
||||
if fips140Enforced() {
|
||||
return nil, errors.New("chacha20poly1305: use of ChaCha20Poly1305 is not allowed in FIPS 140-only mode")
|
||||
}
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20poly1305: bad key length")
|
||||
}
|
||||
|
||||
+8
-2
@@ -56,7 +56,10 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+16)
|
||||
if alias.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
||||
return ret
|
||||
@@ -73,7 +76,10 @@ func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) (
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if alias.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
||||
for i := range out {
|
||||
|
||||
+8
-2
@@ -31,7 +31,10 @@ func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []b
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
|
||||
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
|
||||
if alias.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
|
||||
var polyKey [32]byte
|
||||
@@ -67,7 +70,10 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []
|
||||
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if alias.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
if !p.Verify(tag) {
|
||||
for i := range out {
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Copyright 2025 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.
|
||||
|
||||
//go:build !go1.26
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
func fips140Enforced() bool { return false }
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2025 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.
|
||||
|
||||
//go:build go1.26
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
import "crypto/fips140"
|
||||
|
||||
func fips140Enforced() bool { return fips140.Enforced() }
|
||||
+3
@@ -22,6 +22,9 @@ type xchacha20poly1305 struct {
|
||||
// preferred when nonce uniqueness cannot be trivially ensured, or whenever
|
||||
// nonces are randomly generated.
|
||||
func NewX(key []byte) (cipher.AEAD, error) {
|
||||
if fips140Enforced() {
|
||||
return nil, errors.New("chacha20poly1305: use of ChaCha20Poly1305 is not allowed in FIPS 140-only mode")
|
||||
}
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20poly1305: bad key length")
|
||||
}
|
||||
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
// Copyright 2014 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 sha3 implements the SHA-3 fixed-output-length hash functions and
|
||||
// the SHAKE variable-output-length hash functions defined by FIPS-202.
|
||||
//
|
||||
// All types in this package also implement [encoding.BinaryMarshaler],
|
||||
// [encoding.BinaryAppender] and [encoding.BinaryUnmarshaler] to marshal and
|
||||
// unmarshal the internal state of the hash.
|
||||
//
|
||||
// Both types of hash function use the "sponge" construction and the Keccak
|
||||
// permutation. For a detailed specification see http://keccak.noekeon.org/
|
||||
//
|
||||
// # Guidance
|
||||
//
|
||||
// If you aren't sure what function you need, use SHAKE256 with at least 64
|
||||
// bytes of output. The SHAKE instances are faster than the SHA3 instances;
|
||||
// the latter have to allocate memory to conform to the hash.Hash interface.
|
||||
//
|
||||
// If you need a secret-key MAC (message authentication code), prepend the
|
||||
// secret key to the input, hash with SHAKE256 and read at least 32 bytes of
|
||||
// output.
|
||||
//
|
||||
// # Security strengths
|
||||
//
|
||||
// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security
|
||||
// strength against preimage attacks of x bits. Since they only produce "x"
|
||||
// bits of output, their collision-resistance is only "x/2" bits.
|
||||
//
|
||||
// The SHAKE-256 and -128 functions have a generic security strength of 256 and
|
||||
// 128 bits against all attacks, provided that at least 2x bits of their output
|
||||
// is used. Requesting more than 64 or 32 bytes of output, respectively, does
|
||||
// not increase the collision-resistance of the SHAKE functions.
|
||||
//
|
||||
// # The sponge construction
|
||||
//
|
||||
// A sponge builds a pseudo-random function from a public pseudo-random
|
||||
// permutation, by applying the permutation to a state of "rate + capacity"
|
||||
// bytes, but hiding "capacity" of the bytes.
|
||||
//
|
||||
// A sponge starts out with a zero state. To hash an input using a sponge, up
|
||||
// to "rate" bytes of the input are XORed into the sponge's state. The sponge
|
||||
// is then "full" and the permutation is applied to "empty" it. This process is
|
||||
// repeated until all the input has been "absorbed". The input is then padded.
|
||||
// The digest is "squeezed" from the sponge in the same way, except that output
|
||||
// is copied out instead of input being XORed in.
|
||||
//
|
||||
// A sponge is parameterized by its generic security strength, which is equal
|
||||
// to half its capacity; capacity + rate is equal to the permutation's width.
|
||||
// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means
|
||||
// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
|
||||
//
|
||||
// # Recommendations
|
||||
//
|
||||
// The SHAKE functions are recommended for most new uses. They can produce
|
||||
// output of arbitrary length. SHAKE256, with an output length of at least
|
||||
// 64 bytes, provides 256-bit security against all attacks. The Keccak team
|
||||
// recommends it for most applications upgrading from SHA2-512. (NIST chose a
|
||||
// much stronger, but much slower, sponge instance for SHA3-512.)
|
||||
//
|
||||
// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions.
|
||||
// They produce output of the same length, with the same security strengths
|
||||
// against all attacks. This means, in particular, that SHA3-256 only has
|
||||
// 128-bit collision resistance, because its output length is 32 bytes.
|
||||
package sha3
|
||||
+50
-83
@@ -2,127 +2,94 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package sha3 implements the SHA-3 hash algorithms and the SHAKE extendable
|
||||
// output functions defined in FIPS 202.
|
||||
//
|
||||
// Most of this package is a wrapper around the crypto/sha3 package in the
|
||||
// standard library. The only exception is the legacy Keccak hash functions.
|
||||
package sha3
|
||||
|
||||
// This file provides functions for creating instances of the SHA-3
|
||||
// and SHAKE hash functions, as well as utility functions for hashing
|
||||
// bytes.
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/sha3"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// New224 creates a new SHA3-224 hash.
|
||||
// Its generic security strength is 224 bits against preimage attacks,
|
||||
// and 112 bits against collision attacks.
|
||||
//
|
||||
// It is a wrapper for the [sha3.New224] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func New224() hash.Hash {
|
||||
return new224()
|
||||
return sha3.New224()
|
||||
}
|
||||
|
||||
// New256 creates a new SHA3-256 hash.
|
||||
// Its generic security strength is 256 bits against preimage attacks,
|
||||
// and 128 bits against collision attacks.
|
||||
//
|
||||
// It is a wrapper for the [sha3.New256] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func New256() hash.Hash {
|
||||
return new256()
|
||||
return sha3.New256()
|
||||
}
|
||||
|
||||
// New384 creates a new SHA3-384 hash.
|
||||
// Its generic security strength is 384 bits against preimage attacks,
|
||||
// and 192 bits against collision attacks.
|
||||
//
|
||||
// It is a wrapper for the [sha3.New384] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func New384() hash.Hash {
|
||||
return new384()
|
||||
return sha3.New384()
|
||||
}
|
||||
|
||||
// New512 creates a new SHA3-512 hash.
|
||||
// Its generic security strength is 512 bits against preimage attacks,
|
||||
// and 256 bits against collision attacks.
|
||||
//
|
||||
// It is a wrapper for the [sha3.New512] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func New512() hash.Hash {
|
||||
return new512()
|
||||
}
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.SHA3_224, New224)
|
||||
crypto.RegisterHash(crypto.SHA3_256, New256)
|
||||
crypto.RegisterHash(crypto.SHA3_384, New384)
|
||||
crypto.RegisterHash(crypto.SHA3_512, New512)
|
||||
}
|
||||
|
||||
const (
|
||||
dsbyteSHA3 = 0b00000110
|
||||
dsbyteKeccak = 0b00000001
|
||||
dsbyteShake = 0b00011111
|
||||
dsbyteCShake = 0b00000100
|
||||
|
||||
// rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in
|
||||
// bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits.
|
||||
rateK256 = (1600 - 256) / 8
|
||||
rateK448 = (1600 - 448) / 8
|
||||
rateK512 = (1600 - 512) / 8
|
||||
rateK768 = (1600 - 768) / 8
|
||||
rateK1024 = (1600 - 1024) / 8
|
||||
)
|
||||
|
||||
func new224Generic() *state {
|
||||
return &state{rate: rateK448, outputLen: 28, dsbyte: dsbyteSHA3}
|
||||
}
|
||||
|
||||
func new256Generic() *state {
|
||||
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteSHA3}
|
||||
}
|
||||
|
||||
func new384Generic() *state {
|
||||
return &state{rate: rateK768, outputLen: 48, dsbyte: dsbyteSHA3}
|
||||
}
|
||||
|
||||
func new512Generic() *state {
|
||||
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteSHA3}
|
||||
}
|
||||
|
||||
// NewLegacyKeccak256 creates a new Keccak-256 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New256 instead.
|
||||
func NewLegacyKeccak256() hash.Hash {
|
||||
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak}
|
||||
}
|
||||
|
||||
// NewLegacyKeccak512 creates a new Keccak-512 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New512 instead.
|
||||
func NewLegacyKeccak512() hash.Hash {
|
||||
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak}
|
||||
return sha3.New512()
|
||||
}
|
||||
|
||||
// Sum224 returns the SHA3-224 digest of the data.
|
||||
func Sum224(data []byte) (digest [28]byte) {
|
||||
h := New224()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
//
|
||||
// It is a wrapper for the [sha3.Sum224] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func Sum224(data []byte) [28]byte {
|
||||
return sha3.Sum224(data)
|
||||
}
|
||||
|
||||
// Sum256 returns the SHA3-256 digest of the data.
|
||||
func Sum256(data []byte) (digest [32]byte) {
|
||||
h := New256()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
//
|
||||
// It is a wrapper for the [sha3.Sum256] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func Sum256(data []byte) [32]byte {
|
||||
return sha3.Sum256(data)
|
||||
}
|
||||
|
||||
// Sum384 returns the SHA3-384 digest of the data.
|
||||
func Sum384(data []byte) (digest [48]byte) {
|
||||
h := New384()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
//
|
||||
// It is a wrapper for the [sha3.Sum384] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func Sum384(data []byte) [48]byte {
|
||||
return sha3.Sum384(data)
|
||||
}
|
||||
|
||||
// Sum512 returns the SHA3-512 digest of the data.
|
||||
func Sum512(data []byte) (digest [64]byte) {
|
||||
h := New512()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
//
|
||||
// It is a wrapper for the [sha3.Sum512] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func Sum512(data []byte) [64]byte {
|
||||
return sha3.Sum512(data)
|
||||
}
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
//go:build !gc || purego || !s390x
|
||||
|
||||
package sha3
|
||||
|
||||
func new224() *state {
|
||||
return new224Generic()
|
||||
}
|
||||
|
||||
func new256() *state {
|
||||
return new256Generic()
|
||||
}
|
||||
|
||||
func new384() *state {
|
||||
return new384Generic()
|
||||
}
|
||||
|
||||
func new512() *state {
|
||||
return new512Generic()
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
//go:build amd64 && !purego && gc
|
||||
|
||||
package sha3
|
||||
|
||||
// This function is implemented in keccakf_amd64.s.
|
||||
|
||||
//go:noescape
|
||||
|
||||
func keccakF1600(a *[25]uint64)
|
||||
-5419
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+34
-15
@@ -4,15 +4,46 @@
|
||||
|
||||
package sha3
|
||||
|
||||
// This implementation is only used for NewLegacyKeccak256 and
|
||||
// NewLegacyKeccak512, which are not implemented by crypto/sha3.
|
||||
// All other functions in this package are wrappers around crypto/sha3.
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
const (
|
||||
dsbyteKeccak = 0b00000001
|
||||
|
||||
// rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in
|
||||
// bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits.
|
||||
rateK256 = (1600 - 256) / 8
|
||||
rateK512 = (1600 - 512) / 8
|
||||
rateK1024 = (1600 - 1024) / 8
|
||||
)
|
||||
|
||||
// NewLegacyKeccak256 creates a new Keccak-256 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New256 instead.
|
||||
func NewLegacyKeccak256() hash.Hash {
|
||||
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak}
|
||||
}
|
||||
|
||||
// NewLegacyKeccak512 creates a new Keccak-512 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New512 instead.
|
||||
func NewLegacyKeccak512() hash.Hash {
|
||||
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak}
|
||||
}
|
||||
|
||||
// spongeDirection indicates the direction bytes are flowing through the sponge.
|
||||
type spongeDirection int
|
||||
|
||||
@@ -173,12 +204,9 @@ func (d *state) Sum(in []byte) []byte {
|
||||
}
|
||||
|
||||
const (
|
||||
magicSHA3 = "sha\x08"
|
||||
magicShake = "sha\x09"
|
||||
magicCShake = "sha\x0a"
|
||||
magicKeccak = "sha\x0b"
|
||||
// magic || rate || main state || n || sponge direction
|
||||
marshaledSize = len(magicSHA3) + 1 + 200 + 1 + 1
|
||||
marshaledSize = len(magicKeccak) + 1 + 200 + 1 + 1
|
||||
)
|
||||
|
||||
func (d *state) MarshalBinary() ([]byte, error) {
|
||||
@@ -187,12 +215,6 @@ func (d *state) MarshalBinary() ([]byte, error) {
|
||||
|
||||
func (d *state) AppendBinary(b []byte) ([]byte, error) {
|
||||
switch d.dsbyte {
|
||||
case dsbyteSHA3:
|
||||
b = append(b, magicSHA3...)
|
||||
case dsbyteShake:
|
||||
b = append(b, magicShake...)
|
||||
case dsbyteCShake:
|
||||
b = append(b, magicCShake...)
|
||||
case dsbyteKeccak:
|
||||
b = append(b, magicKeccak...)
|
||||
default:
|
||||
@@ -210,12 +232,9 @@ func (d *state) UnmarshalBinary(b []byte) error {
|
||||
return errors.New("sha3: invalid hash state")
|
||||
}
|
||||
|
||||
magic := string(b[:len(magicSHA3)])
|
||||
b = b[len(magicSHA3):]
|
||||
magic := string(b[:len(magicKeccak)])
|
||||
b = b[len(magicKeccak):]
|
||||
switch {
|
||||
case magic == magicSHA3 && d.dsbyte == dsbyteSHA3:
|
||||
case magic == magicShake && d.dsbyte == dsbyteShake:
|
||||
case magic == magicCShake && d.dsbyte == dsbyteCShake:
|
||||
case magic == magicKeccak && d.dsbyte == dsbyteKeccak:
|
||||
default:
|
||||
return errors.New("sha3: invalid hash state identifier")
|
||||
Generated
Vendored
+4
-2
@@ -2,10 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || purego || !gc
|
||||
|
||||
package sha3
|
||||
|
||||
// This implementation is only used for NewLegacyKeccak256 and
|
||||
// NewLegacyKeccak512, which are not implemented by crypto/sha3.
|
||||
// All other functions in this package are wrappers around crypto/sha3.
|
||||
|
||||
import "math/bits"
|
||||
|
||||
// rc stores the round constants for use in the ι step.
|
||||
-303
@@ -1,303 +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.
|
||||
|
||||
//go:build gc && !purego
|
||||
|
||||
package sha3
|
||||
|
||||
// This file contains code for using the 'compute intermediate
|
||||
// message digest' (KIMD) and 'compute last message digest' (KLMD)
|
||||
// instructions to compute SHA-3 and SHAKE hashes on IBM Z.
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
// codes represent 7-bit KIMD/KLMD function codes as defined in
|
||||
// the Principles of Operation.
|
||||
type code uint64
|
||||
|
||||
const (
|
||||
// function codes for KIMD/KLMD
|
||||
sha3_224 code = 32
|
||||
sha3_256 = 33
|
||||
sha3_384 = 34
|
||||
sha3_512 = 35
|
||||
shake_128 = 36
|
||||
shake_256 = 37
|
||||
nopad = 0x100
|
||||
)
|
||||
|
||||
// kimd is a wrapper for the 'compute intermediate message digest' instruction.
|
||||
// src must be a multiple of the rate for the given function code.
|
||||
//
|
||||
//go:noescape
|
||||
func kimd(function code, chain *[200]byte, src []byte)
|
||||
|
||||
// klmd is a wrapper for the 'compute last message digest' instruction.
|
||||
// src padding is handled by the instruction.
|
||||
//
|
||||
//go:noescape
|
||||
func klmd(function code, chain *[200]byte, dst, src []byte)
|
||||
|
||||
type asmState struct {
|
||||
a [200]byte // 1600 bit state
|
||||
buf []byte // care must be taken to ensure cap(buf) is a multiple of rate
|
||||
rate int // equivalent to block size
|
||||
storage [3072]byte // underlying storage for buf
|
||||
outputLen int // output length for full security
|
||||
function code // KIMD/KLMD function code
|
||||
state spongeDirection // whether the sponge is absorbing or squeezing
|
||||
}
|
||||
|
||||
func newAsmState(function code) *asmState {
|
||||
var s asmState
|
||||
s.function = function
|
||||
switch function {
|
||||
case sha3_224:
|
||||
s.rate = 144
|
||||
s.outputLen = 28
|
||||
case sha3_256:
|
||||
s.rate = 136
|
||||
s.outputLen = 32
|
||||
case sha3_384:
|
||||
s.rate = 104
|
||||
s.outputLen = 48
|
||||
case sha3_512:
|
||||
s.rate = 72
|
||||
s.outputLen = 64
|
||||
case shake_128:
|
||||
s.rate = 168
|
||||
s.outputLen = 32
|
||||
case shake_256:
|
||||
s.rate = 136
|
||||
s.outputLen = 64
|
||||
default:
|
||||
panic("sha3: unrecognized function code")
|
||||
}
|
||||
|
||||
// limit s.buf size to a multiple of s.rate
|
||||
s.resetBuf()
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s *asmState) clone() *asmState {
|
||||
c := *s
|
||||
c.buf = c.storage[:len(s.buf):cap(s.buf)]
|
||||
return &c
|
||||
}
|
||||
|
||||
// copyIntoBuf copies b into buf. It will panic if there is not enough space to
|
||||
// store all of b.
|
||||
func (s *asmState) copyIntoBuf(b []byte) {
|
||||
bufLen := len(s.buf)
|
||||
s.buf = s.buf[:len(s.buf)+len(b)]
|
||||
copy(s.buf[bufLen:], b)
|
||||
}
|
||||
|
||||
// resetBuf points buf at storage, sets the length to 0 and sets cap to be a
|
||||
// multiple of the rate.
|
||||
func (s *asmState) resetBuf() {
|
||||
max := (cap(s.storage) / s.rate) * s.rate
|
||||
s.buf = s.storage[:0:max]
|
||||
}
|
||||
|
||||
// Write (via the embedded io.Writer interface) adds more data to the running hash.
|
||||
// It never returns an error.
|
||||
func (s *asmState) Write(b []byte) (int, error) {
|
||||
if s.state != spongeAbsorbing {
|
||||
panic("sha3: Write after Read")
|
||||
}
|
||||
length := len(b)
|
||||
for len(b) > 0 {
|
||||
if len(s.buf) == 0 && len(b) >= cap(s.buf) {
|
||||
// Hash the data directly and push any remaining bytes
|
||||
// into the buffer.
|
||||
remainder := len(b) % s.rate
|
||||
kimd(s.function, &s.a, b[:len(b)-remainder])
|
||||
if remainder != 0 {
|
||||
s.copyIntoBuf(b[len(b)-remainder:])
|
||||
}
|
||||
return length, nil
|
||||
}
|
||||
|
||||
if len(s.buf) == cap(s.buf) {
|
||||
// flush the buffer
|
||||
kimd(s.function, &s.a, s.buf)
|
||||
s.buf = s.buf[:0]
|
||||
}
|
||||
|
||||
// copy as much as we can into the buffer
|
||||
n := len(b)
|
||||
if len(b) > cap(s.buf)-len(s.buf) {
|
||||
n = cap(s.buf) - len(s.buf)
|
||||
}
|
||||
s.copyIntoBuf(b[:n])
|
||||
b = b[n:]
|
||||
}
|
||||
return length, nil
|
||||
}
|
||||
|
||||
// Read squeezes an arbitrary number of bytes from the sponge.
|
||||
func (s *asmState) Read(out []byte) (n int, err error) {
|
||||
// The 'compute last message digest' instruction only stores the digest
|
||||
// at the first operand (dst) for SHAKE functions.
|
||||
if s.function != shake_128 && s.function != shake_256 {
|
||||
panic("sha3: can only call Read for SHAKE functions")
|
||||
}
|
||||
|
||||
n = len(out)
|
||||
|
||||
// need to pad if we were absorbing
|
||||
if s.state == spongeAbsorbing {
|
||||
s.state = spongeSqueezing
|
||||
|
||||
// write hash directly into out if possible
|
||||
if len(out)%s.rate == 0 {
|
||||
klmd(s.function, &s.a, out, s.buf) // len(out) may be 0
|
||||
s.buf = s.buf[:0]
|
||||
return
|
||||
}
|
||||
|
||||
// write hash into buffer
|
||||
max := cap(s.buf)
|
||||
if max > len(out) {
|
||||
max = (len(out)/s.rate)*s.rate + s.rate
|
||||
}
|
||||
klmd(s.function, &s.a, s.buf[:max], s.buf)
|
||||
s.buf = s.buf[:max]
|
||||
}
|
||||
|
||||
for len(out) > 0 {
|
||||
// flush the buffer
|
||||
if len(s.buf) != 0 {
|
||||
c := copy(out, s.buf)
|
||||
out = out[c:]
|
||||
s.buf = s.buf[c:]
|
||||
continue
|
||||
}
|
||||
|
||||
// write hash directly into out if possible
|
||||
if len(out)%s.rate == 0 {
|
||||
klmd(s.function|nopad, &s.a, out, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// write hash into buffer
|
||||
s.resetBuf()
|
||||
if cap(s.buf) > len(out) {
|
||||
s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate]
|
||||
}
|
||||
klmd(s.function|nopad, &s.a, s.buf, nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Sum appends the current hash to b and returns the resulting slice.
|
||||
// It does not change the underlying hash state.
|
||||
func (s *asmState) Sum(b []byte) []byte {
|
||||
if s.state != spongeAbsorbing {
|
||||
panic("sha3: Sum after Read")
|
||||
}
|
||||
|
||||
// Copy the state to preserve the original.
|
||||
a := s.a
|
||||
|
||||
// Hash the buffer. Note that we don't clear it because we
|
||||
// aren't updating the state.
|
||||
switch s.function {
|
||||
case sha3_224, sha3_256, sha3_384, sha3_512:
|
||||
klmd(s.function, &a, nil, s.buf)
|
||||
return append(b, a[:s.outputLen]...)
|
||||
case shake_128, shake_256:
|
||||
d := make([]byte, s.outputLen, 64)
|
||||
klmd(s.function, &a, d, s.buf)
|
||||
return append(b, d[:s.outputLen]...)
|
||||
default:
|
||||
panic("sha3: unknown function")
|
||||
}
|
||||
}
|
||||
|
||||
// Reset resets the Hash to its initial state.
|
||||
func (s *asmState) Reset() {
|
||||
for i := range s.a {
|
||||
s.a[i] = 0
|
||||
}
|
||||
s.resetBuf()
|
||||
s.state = spongeAbsorbing
|
||||
}
|
||||
|
||||
// Size returns the number of bytes Sum will return.
|
||||
func (s *asmState) Size() int {
|
||||
return s.outputLen
|
||||
}
|
||||
|
||||
// BlockSize returns the hash's underlying block size.
|
||||
// The Write method must be able to accept any amount
|
||||
// of data, but it may operate more efficiently if all writes
|
||||
// are a multiple of the block size.
|
||||
func (s *asmState) BlockSize() int {
|
||||
return s.rate
|
||||
}
|
||||
|
||||
// Clone returns a copy of the ShakeHash in its current state.
|
||||
func (s *asmState) Clone() ShakeHash {
|
||||
return s.clone()
|
||||
}
|
||||
|
||||
// new224 returns an assembly implementation of SHA3-224 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func new224() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_224)
|
||||
}
|
||||
return new224Generic()
|
||||
}
|
||||
|
||||
// new256 returns an assembly implementation of SHA3-256 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func new256() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_256)
|
||||
}
|
||||
return new256Generic()
|
||||
}
|
||||
|
||||
// new384 returns an assembly implementation of SHA3-384 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func new384() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_384)
|
||||
}
|
||||
return new384Generic()
|
||||
}
|
||||
|
||||
// new512 returns an assembly implementation of SHA3-512 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func new512() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_512)
|
||||
}
|
||||
return new512Generic()
|
||||
}
|
||||
|
||||
// newShake128 returns an assembly implementation of SHAKE-128 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func newShake128() ShakeHash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(shake_128)
|
||||
}
|
||||
return newShake128Generic()
|
||||
}
|
||||
|
||||
// newShake256 returns an assembly implementation of SHAKE-256 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func newShake256() ShakeHash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(shake_256)
|
||||
}
|
||||
return newShake256Generic()
|
||||
}
|
||||
-33
@@ -1,33 +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.
|
||||
|
||||
//go:build gc && !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func kimd(function code, chain *[200]byte, src []byte)
|
||||
TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40
|
||||
MOVD function+0(FP), R0
|
||||
MOVD chain+8(FP), R1
|
||||
LMG src+16(FP), R2, R3 // R2=base, R3=len
|
||||
|
||||
continue:
|
||||
WORD $0xB93E0002 // KIMD --, R2
|
||||
BVS continue // continue if interrupted
|
||||
MOVD $0, R0 // reset R0 for pre-go1.8 compilers
|
||||
RET
|
||||
|
||||
// func klmd(function code, chain *[200]byte, dst, src []byte)
|
||||
TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64
|
||||
// TODO: SHAKE support
|
||||
MOVD function+0(FP), R0
|
||||
MOVD chain+8(FP), R1
|
||||
LMG dst+16(FP), R2, R3 // R2=base, R3=len
|
||||
LMG src+40(FP), R4, R5 // R4=base, R5=len
|
||||
|
||||
continue:
|
||||
WORD $0xB93F0024 // KLMD R2, R4
|
||||
BVS continue // continue if interrupted
|
||||
MOVD $0, R0 // reset R0 for pre-go1.8 compilers
|
||||
RET
|
||||
+49
-123
@@ -4,24 +4,10 @@
|
||||
|
||||
package sha3
|
||||
|
||||
// This file defines the ShakeHash interface, and provides
|
||||
// functions for creating SHAKE and cSHAKE instances, as well as utility
|
||||
// functions for hashing bytes to arbitrary-length output.
|
||||
//
|
||||
//
|
||||
// SHAKE implementation is based on FIPS PUB 202 [1]
|
||||
// cSHAKE implementations is based on NIST SP 800-185 [2]
|
||||
//
|
||||
// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
|
||||
// [2] https://doi.org/10.6028/NIST.SP.800-185
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"crypto/sha3"
|
||||
"hash"
|
||||
"io"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// ShakeHash defines the interface to hash functions that support
|
||||
@@ -32,7 +18,7 @@ type ShakeHash interface {
|
||||
hash.Hash
|
||||
|
||||
// Read reads more output from the hash; reading affects the hash's
|
||||
// state. (ShakeHash.Read is thus very different from Hash.Sum)
|
||||
// state. (ShakeHash.Read is thus very different from Hash.Sum.)
|
||||
// It never returns an error, but subsequent calls to Write or Sum
|
||||
// will panic.
|
||||
io.Reader
|
||||
@@ -41,115 +27,18 @@ type ShakeHash interface {
|
||||
Clone() ShakeHash
|
||||
}
|
||||
|
||||
// cSHAKE specific context
|
||||
type cshakeState struct {
|
||||
*state // SHA-3 state context and Read/Write operations
|
||||
|
||||
// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
|
||||
// by newCShake function and stores concatenation of N followed by S, encoded
|
||||
// by the method specified in 3.3 of [1].
|
||||
// It is stored here in order for Reset() to be able to put context into
|
||||
// initial state.
|
||||
initBlock []byte
|
||||
}
|
||||
|
||||
func bytepad(data []byte, rate int) []byte {
|
||||
out := make([]byte, 0, 9+len(data)+rate-1)
|
||||
out = append(out, leftEncode(uint64(rate))...)
|
||||
out = append(out, data...)
|
||||
if padlen := rate - len(out)%rate; padlen < rate {
|
||||
out = append(out, make([]byte, padlen)...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func leftEncode(x uint64) []byte {
|
||||
// Let n be the smallest positive integer for which 2^(8n) > x.
|
||||
n := (bits.Len64(x) + 7) / 8
|
||||
if n == 0 {
|
||||
n = 1
|
||||
}
|
||||
// Return n || x with n as a byte and x an n bytes in big-endian order.
|
||||
b := make([]byte, 9)
|
||||
binary.BigEndian.PutUint64(b[1:], x)
|
||||
b = b[9-n-1:]
|
||||
b[0] = byte(n)
|
||||
return b
|
||||
}
|
||||
|
||||
func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
|
||||
c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}}
|
||||
c.initBlock = make([]byte, 0, 9+len(N)+9+len(S)) // leftEncode returns max 9 bytes
|
||||
c.initBlock = append(c.initBlock, leftEncode(uint64(len(N))*8)...)
|
||||
c.initBlock = append(c.initBlock, N...)
|
||||
c.initBlock = append(c.initBlock, leftEncode(uint64(len(S))*8)...)
|
||||
c.initBlock = append(c.initBlock, S...)
|
||||
c.Write(bytepad(c.initBlock, c.rate))
|
||||
return &c
|
||||
}
|
||||
|
||||
// Reset resets the hash to initial state.
|
||||
func (c *cshakeState) Reset() {
|
||||
c.state.Reset()
|
||||
c.Write(bytepad(c.initBlock, c.rate))
|
||||
}
|
||||
|
||||
// Clone returns copy of a cSHAKE context within its current state.
|
||||
func (c *cshakeState) Clone() ShakeHash {
|
||||
b := make([]byte, len(c.initBlock))
|
||||
copy(b, c.initBlock)
|
||||
return &cshakeState{state: c.clone(), initBlock: b}
|
||||
}
|
||||
|
||||
// Clone returns copy of SHAKE context within its current state.
|
||||
func (c *state) Clone() ShakeHash {
|
||||
return c.clone()
|
||||
}
|
||||
|
||||
func (c *cshakeState) MarshalBinary() ([]byte, error) {
|
||||
return c.AppendBinary(make([]byte, 0, marshaledSize+len(c.initBlock)))
|
||||
}
|
||||
|
||||
func (c *cshakeState) AppendBinary(b []byte) ([]byte, error) {
|
||||
b, err := c.state.AppendBinary(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = append(b, c.initBlock...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (c *cshakeState) UnmarshalBinary(b []byte) error {
|
||||
if len(b) <= marshaledSize {
|
||||
return errors.New("sha3: invalid hash state")
|
||||
}
|
||||
if err := c.state.UnmarshalBinary(b[:marshaledSize]); err != nil {
|
||||
return err
|
||||
}
|
||||
c.initBlock = bytes.Clone(b[marshaledSize:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 128 bits against all attacks if at
|
||||
// least 32 bytes of its output are used.
|
||||
func NewShake128() ShakeHash {
|
||||
return newShake128()
|
||||
return &shakeWrapper{sha3.NewSHAKE128(), 32, false, sha3.NewSHAKE128}
|
||||
}
|
||||
|
||||
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 256 bits against all attacks if
|
||||
// at least 64 bytes of its output are used.
|
||||
func NewShake256() ShakeHash {
|
||||
return newShake256()
|
||||
}
|
||||
|
||||
func newShake128Generic() *state {
|
||||
return &state{rate: rateK256, outputLen: 32, dsbyte: dsbyteShake}
|
||||
}
|
||||
|
||||
func newShake256Generic() *state {
|
||||
return &state{rate: rateK512, outputLen: 64, dsbyte: dsbyteShake}
|
||||
return &shakeWrapper{sha3.NewSHAKE256(), 64, false, sha3.NewSHAKE256}
|
||||
}
|
||||
|
||||
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
|
||||
@@ -159,10 +48,9 @@ func newShake256Generic() *state {
|
||||
// computations on same input with different S yield unrelated outputs.
|
||||
// When N and S are both empty, this is equivalent to NewShake128.
|
||||
func NewCShake128(N, S []byte) ShakeHash {
|
||||
if len(N) == 0 && len(S) == 0 {
|
||||
return NewShake128()
|
||||
}
|
||||
return newCShake(N, S, rateK256, 32, dsbyteCShake)
|
||||
return &shakeWrapper{sha3.NewCSHAKE128(N, S), 32, false, func() *sha3.SHAKE {
|
||||
return sha3.NewCSHAKE128(N, S)
|
||||
}}
|
||||
}
|
||||
|
||||
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
|
||||
@@ -172,10 +60,9 @@ func NewCShake128(N, S []byte) ShakeHash {
|
||||
// computations on same input with different S yield unrelated outputs.
|
||||
// When N and S are both empty, this is equivalent to NewShake256.
|
||||
func NewCShake256(N, S []byte) ShakeHash {
|
||||
if len(N) == 0 && len(S) == 0 {
|
||||
return NewShake256()
|
||||
}
|
||||
return newCShake(N, S, rateK512, 64, dsbyteCShake)
|
||||
return &shakeWrapper{sha3.NewCSHAKE256(N, S), 64, false, func() *sha3.SHAKE {
|
||||
return sha3.NewCSHAKE256(N, S)
|
||||
}}
|
||||
}
|
||||
|
||||
// ShakeSum128 writes an arbitrary-length digest of data into hash.
|
||||
@@ -191,3 +78,42 @@ func ShakeSum256(hash, data []byte) {
|
||||
h.Write(data)
|
||||
h.Read(hash)
|
||||
}
|
||||
|
||||
// shakeWrapper adds the Size, Sum, and Clone methods to a sha3.SHAKE
|
||||
// to implement the ShakeHash interface.
|
||||
type shakeWrapper struct {
|
||||
*sha3.SHAKE
|
||||
outputLen int
|
||||
squeezing bool
|
||||
newSHAKE func() *sha3.SHAKE
|
||||
}
|
||||
|
||||
func (w *shakeWrapper) Read(p []byte) (n int, err error) {
|
||||
w.squeezing = true
|
||||
return w.SHAKE.Read(p)
|
||||
}
|
||||
|
||||
func (w *shakeWrapper) Clone() ShakeHash {
|
||||
s := w.newSHAKE()
|
||||
b, err := w.MarshalBinary()
|
||||
if err != nil {
|
||||
panic(err) // unreachable
|
||||
}
|
||||
if err := s.UnmarshalBinary(b); err != nil {
|
||||
panic(err) // unreachable
|
||||
}
|
||||
return &shakeWrapper{s, w.outputLen, w.squeezing, w.newSHAKE}
|
||||
}
|
||||
|
||||
func (w *shakeWrapper) Size() int { return w.outputLen }
|
||||
|
||||
func (w *shakeWrapper) Sum(b []byte) []byte {
|
||||
if w.squeezing {
|
||||
panic("sha3: Sum after Read")
|
||||
}
|
||||
out := make([]byte, w.outputLen)
|
||||
// Clone the state so that we don't affect future Write calls.
|
||||
s := w.Clone()
|
||||
s.Read(out)
|
||||
return append(b, out...)
|
||||
}
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
//go:build !gc || purego || !s390x
|
||||
|
||||
package sha3
|
||||
|
||||
func newShake128() *state {
|
||||
return newShake128Generic()
|
||||
}
|
||||
|
||||
func newShake256() *state {
|
||||
return newShake256Generic()
|
||||
}
|
||||
+1
-1
@@ -33,7 +33,7 @@ type printer struct {
|
||||
}
|
||||
|
||||
// printf prints to the buffer.
|
||||
func (p *printer) printf(format string, args ...interface{}) {
|
||||
func (p *printer) printf(format string, args ...any) {
|
||||
fmt.Fprintf(p, format, args...)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -94,7 +94,7 @@ func (x *FileSyntax) Span() (start, end Position) {
|
||||
// line, the new line is added at the end of the block containing hint,
|
||||
// extracting hint into a new block if it is not yet in one.
|
||||
//
|
||||
// If the hint is non-nil buts its first token does not match,
|
||||
// If the hint is non-nil but its first token does not match,
|
||||
// the new line is added after the block containing hint
|
||||
// (or hint itself, if not in a block).
|
||||
//
|
||||
@@ -600,7 +600,7 @@ func (in *input) readToken() {
|
||||
|
||||
// Checked all punctuation. Must be identifier token.
|
||||
if c := in.peekRune(); !isIdent(c) {
|
||||
in.Error(fmt.Sprintf("unexpected input character %#q", c))
|
||||
in.Error(fmt.Sprintf("unexpected input character %#q", rune(c)))
|
||||
}
|
||||
|
||||
// Scan over identifier.
|
||||
|
||||
+4
-4
@@ -368,7 +368,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
|
||||
Err: err,
|
||||
})
|
||||
}
|
||||
errorf := func(format string, args ...interface{}) {
|
||||
errorf := func(format string, args ...any) {
|
||||
wrapError(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
@@ -574,7 +574,7 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
errorf := func(format string, args ...interface{}) *Error {
|
||||
errorf := func(format string, args ...any) *Error {
|
||||
return wrapError(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
@@ -685,7 +685,7 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string,
|
||||
Err: err,
|
||||
})
|
||||
}
|
||||
errorf := func(format string, args ...interface{}) {
|
||||
errorf := func(format string, args ...any) {
|
||||
wrapError(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
@@ -1594,7 +1594,7 @@ func (f *File) AddRetract(vi VersionInterval, rationale string) error {
|
||||
r.Syntax = f.Syntax.addLine(nil, "retract", "[", AutoQuote(vi.Low), ",", AutoQuote(vi.High), "]")
|
||||
}
|
||||
if rationale != "" {
|
||||
for _, line := range strings.Split(rationale, "\n") {
|
||||
for line := range strings.SplitSeq(rationale, "\n") {
|
||||
com := Comment{Token: "// " + line}
|
||||
r.Syntax.Comment().Before = append(r.Syntax.Comment().Before, com)
|
||||
}
|
||||
|
||||
+3
-3
@@ -261,7 +261,7 @@ func modPathOK(r rune) bool {
|
||||
|
||||
// importPathOK reports whether r can appear in a package import path element.
|
||||
//
|
||||
// Import paths are intermediate between module paths and file paths: we allow
|
||||
// Import paths are intermediate between module paths and file paths: we
|
||||
// disallow characters that would be confusing or ambiguous as arguments to
|
||||
// 'go get' (such as '@' and ' ' ), but allow certain characters that are
|
||||
// otherwise-unambiguous on the command line and historically used for some
|
||||
@@ -802,8 +802,8 @@ func MatchPrefixPatterns(globs, target string) bool {
|
||||
for globs != "" {
|
||||
// Extract next non-empty glob in comma-separated list.
|
||||
var glob string
|
||||
if i := strings.Index(globs, ","); i >= 0 {
|
||||
glob, globs = globs[:i], globs[i+1:]
|
||||
if before, after, ok := strings.Cut(globs, ","); ok {
|
||||
glob, globs = before, after
|
||||
} else {
|
||||
glob, globs = globs, ""
|
||||
}
|
||||
|
||||
+2
-2
@@ -45,8 +45,8 @@ func IsValid(v string) bool {
|
||||
|
||||
// Canonical returns the canonical formatting of the semantic version v.
|
||||
// It fills in any missing .MINOR or .PATCH and discards build metadata.
|
||||
// Two semantic versions compare equal only if their canonical formattings
|
||||
// are identical strings.
|
||||
// Two semantic versions compare equal only if their canonical formatting
|
||||
// is an identical string.
|
||||
// The canonical invalid semantic version is the empty string.
|
||||
func Canonical(v string) string {
|
||||
p, ok := parse(v)
|
||||
|
||||
+2
-35
@@ -2,42 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package context defines the Context type, which carries deadlines,
|
||||
// cancellation signals, and other request-scoped values across API boundaries
|
||||
// and between processes.
|
||||
// As of Go 1.7 this package is available in the standard library under the
|
||||
// name [context].
|
||||
// Package context has been superseded by the standard library [context] package.
|
||||
//
|
||||
// Incoming requests to a server should create a [Context], and outgoing
|
||||
// calls to servers should accept a Context. The chain of function
|
||||
// calls between them must propagate the Context, optionally replacing
|
||||
// it with a derived Context created using [WithCancel], [WithDeadline],
|
||||
// [WithTimeout], or [WithValue].
|
||||
//
|
||||
// Programs that use Contexts should follow these rules to keep interfaces
|
||||
// consistent across packages and enable static analysis tools to check context
|
||||
// propagation:
|
||||
//
|
||||
// Do not store Contexts inside a struct type; instead, pass a Context
|
||||
// explicitly to each function that needs it. This is discussed further in
|
||||
// https://go.dev/blog/context-and-structs. The Context should be the first
|
||||
// parameter, typically named ctx:
|
||||
//
|
||||
// func DoSomething(ctx context.Context, arg Arg) error {
|
||||
// // ... use ctx ...
|
||||
// }
|
||||
//
|
||||
// Do not pass a nil [Context], even if a function permits it. Pass [context.TODO]
|
||||
// if you are unsure about which Context to use.
|
||||
//
|
||||
// Use context Values only for request-scoped data that transits processes and
|
||||
// APIs, not for passing optional parameters to functions.
|
||||
//
|
||||
// The same Context may be passed to functions running in different goroutines;
|
||||
// Contexts are safe for simultaneous use by multiple goroutines.
|
||||
//
|
||||
// See https://go.dev/blog/context for example code for a server that uses
|
||||
// Contexts.
|
||||
// Deprecated: Use the standard library context package instead.
|
||||
package context
|
||||
|
||||
import (
|
||||
|
||||
-2
@@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.23
|
||||
|
||||
package html
|
||||
|
||||
import "iter"
|
||||
|
||||
+1
@@ -11,6 +11,7 @@ import (
|
||||
// A NodeType is the type of a Node.
|
||||
type NodeType uint32
|
||||
|
||||
//go:generate stringer -type NodeType
|
||||
const (
|
||||
ErrorNode NodeType = iota
|
||||
TextNode
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// Code generated by "stringer -type NodeType"; DO NOT EDIT.
|
||||
|
||||
package html
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ErrorNode-0]
|
||||
_ = x[TextNode-1]
|
||||
_ = x[DocumentNode-2]
|
||||
_ = x[ElementNode-3]
|
||||
_ = x[CommentNode-4]
|
||||
_ = x[DoctypeNode-5]
|
||||
_ = x[RawNode-6]
|
||||
_ = x[scopeMarkerNode-7]
|
||||
}
|
||||
|
||||
const _NodeType_name = "ErrorNodeTextNodeDocumentNodeElementNodeCommentNodeDoctypeNodeRawNodescopeMarkerNode"
|
||||
|
||||
var _NodeType_index = [...]uint8{0, 9, 17, 29, 40, 51, 62, 69, 84}
|
||||
|
||||
func (i NodeType) String() string {
|
||||
idx := int(i) - 0
|
||||
if i < 0 || idx >= len(_NodeType_index)-1 {
|
||||
return "NodeType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _NodeType_name[_NodeType_index[idx]:_NodeType_index[idx+1]]
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// Copyright 2026 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.
|
||||
|
||||
//go:build !go1.27
|
||||
|
||||
package http2
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Support for go.dev/issue/75500 is added in Go 1.27. In case anyone uses
|
||||
// x/net with versions before Go 1.27, we return true here so that their write
|
||||
// scheduler will still be the round-robin write scheduler rather than the RFC
|
||||
// 9218 write scheduler. That way, older users of Go will not see a sudden
|
||||
// change of behavior just from importing x/net.
|
||||
//
|
||||
// TODO(nsh): remove this file after x/net go.mod is at Go 1.27.
|
||||
func clientPriorityDisabled(_ *http.Server) bool {
|
||||
return true
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// Copyright 2026 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.
|
||||
|
||||
//go:build go1.27
|
||||
|
||||
package http2
|
||||
|
||||
import "net/http"
|
||||
|
||||
func clientPriorityDisabled(s *http.Server) bool {
|
||||
return s.DisableClientPriority
|
||||
}
|
||||
+205
-59
@@ -11,11 +11,13 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/internal/httpsfv"
|
||||
)
|
||||
|
||||
const frameHeaderLen = 9
|
||||
@@ -23,33 +25,36 @@ const frameHeaderLen = 9
|
||||
var padZeros = make([]byte, 255) // zeros for padding
|
||||
|
||||
// A FrameType is a registered frame type as defined in
|
||||
// https://httpwg.org/specs/rfc7540.html#rfc.section.11.2
|
||||
// https://httpwg.org/specs/rfc7540.html#rfc.section.11.2 and other future
|
||||
// RFCs.
|
||||
type FrameType uint8
|
||||
|
||||
const (
|
||||
FrameData FrameType = 0x0
|
||||
FrameHeaders FrameType = 0x1
|
||||
FramePriority FrameType = 0x2
|
||||
FrameRSTStream FrameType = 0x3
|
||||
FrameSettings FrameType = 0x4
|
||||
FramePushPromise FrameType = 0x5
|
||||
FramePing FrameType = 0x6
|
||||
FrameGoAway FrameType = 0x7
|
||||
FrameWindowUpdate FrameType = 0x8
|
||||
FrameContinuation FrameType = 0x9
|
||||
FrameData FrameType = 0x0
|
||||
FrameHeaders FrameType = 0x1
|
||||
FramePriority FrameType = 0x2
|
||||
FrameRSTStream FrameType = 0x3
|
||||
FrameSettings FrameType = 0x4
|
||||
FramePushPromise FrameType = 0x5
|
||||
FramePing FrameType = 0x6
|
||||
FrameGoAway FrameType = 0x7
|
||||
FrameWindowUpdate FrameType = 0x8
|
||||
FrameContinuation FrameType = 0x9
|
||||
FramePriorityUpdate FrameType = 0x10
|
||||
)
|
||||
|
||||
var frameNames = [...]string{
|
||||
FrameData: "DATA",
|
||||
FrameHeaders: "HEADERS",
|
||||
FramePriority: "PRIORITY",
|
||||
FrameRSTStream: "RST_STREAM",
|
||||
FrameSettings: "SETTINGS",
|
||||
FramePushPromise: "PUSH_PROMISE",
|
||||
FramePing: "PING",
|
||||
FrameGoAway: "GOAWAY",
|
||||
FrameWindowUpdate: "WINDOW_UPDATE",
|
||||
FrameContinuation: "CONTINUATION",
|
||||
FrameData: "DATA",
|
||||
FrameHeaders: "HEADERS",
|
||||
FramePriority: "PRIORITY",
|
||||
FrameRSTStream: "RST_STREAM",
|
||||
FrameSettings: "SETTINGS",
|
||||
FramePushPromise: "PUSH_PROMISE",
|
||||
FramePing: "PING",
|
||||
FrameGoAway: "GOAWAY",
|
||||
FrameWindowUpdate: "WINDOW_UPDATE",
|
||||
FrameContinuation: "CONTINUATION",
|
||||
FramePriorityUpdate: "PRIORITY_UPDATE",
|
||||
}
|
||||
|
||||
func (t FrameType) String() string {
|
||||
@@ -125,21 +130,24 @@ var flagName = map[FrameType]map[Flags]string{
|
||||
type frameParser func(fc *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error)
|
||||
|
||||
var frameParsers = [...]frameParser{
|
||||
FrameData: parseDataFrame,
|
||||
FrameHeaders: parseHeadersFrame,
|
||||
FramePriority: parsePriorityFrame,
|
||||
FrameRSTStream: parseRSTStreamFrame,
|
||||
FrameSettings: parseSettingsFrame,
|
||||
FramePushPromise: parsePushPromise,
|
||||
FramePing: parsePingFrame,
|
||||
FrameGoAway: parseGoAwayFrame,
|
||||
FrameWindowUpdate: parseWindowUpdateFrame,
|
||||
FrameContinuation: parseContinuationFrame,
|
||||
FrameData: parseDataFrame,
|
||||
FrameHeaders: parseHeadersFrame,
|
||||
FramePriority: parsePriorityFrame,
|
||||
FrameRSTStream: parseRSTStreamFrame,
|
||||
FrameSettings: parseSettingsFrame,
|
||||
FramePushPromise: parsePushPromise,
|
||||
FramePing: parsePingFrame,
|
||||
FrameGoAway: parseGoAwayFrame,
|
||||
FrameWindowUpdate: parseWindowUpdateFrame,
|
||||
FrameContinuation: parseContinuationFrame,
|
||||
FramePriorityUpdate: parsePriorityUpdateFrame,
|
||||
}
|
||||
|
||||
func typeFrameParser(t FrameType) frameParser {
|
||||
if int(t) < len(frameParsers) {
|
||||
return frameParsers[t]
|
||||
if f := frameParsers[t]; f != nil {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return parseUnknownFrame
|
||||
}
|
||||
@@ -280,6 +288,8 @@ type Framer struct {
|
||||
// lastHeaderStream is non-zero if the last frame was an
|
||||
// unfinished HEADERS/CONTINUATION.
|
||||
lastHeaderStream uint32
|
||||
// lastFrameType holds the type of the last frame for verifying frame order.
|
||||
lastFrameType FrameType
|
||||
|
||||
maxReadSize uint32
|
||||
headerBuf [frameHeaderLen]byte
|
||||
@@ -488,30 +498,41 @@ func terminalReadFrameError(err error) bool {
|
||||
return err != nil
|
||||
}
|
||||
|
||||
// ReadFrame reads a single frame. The returned Frame is only valid
|
||||
// until the next call to ReadFrame.
|
||||
// ReadFrameHeader reads the header of the next frame.
|
||||
// It reads the 9-byte fixed frame header, and does not read any portion of the
|
||||
// frame payload. The caller is responsible for consuming the payload, either
|
||||
// with ReadFrameForHeader or directly from the Framer's io.Reader.
|
||||
//
|
||||
// If the frame is larger than previously set with SetMaxReadFrameSize, the
|
||||
// returned error is ErrFrameTooLarge. Other errors may be of type
|
||||
// ConnectionError, StreamError, or anything else from the underlying
|
||||
// reader.
|
||||
// If the frame is larger than previously set with SetMaxReadFrameSize, it
|
||||
// returns the frame header and ErrFrameTooLarge.
|
||||
//
|
||||
// If ReadFrame returns an error and a non-nil Frame, the Frame's StreamID
|
||||
// indicates the stream responsible for the error.
|
||||
func (fr *Framer) ReadFrame() (Frame, error) {
|
||||
// If the returned FrameHeader.StreamID is non-zero, it indicates the stream
|
||||
// responsible for the error.
|
||||
func (fr *Framer) ReadFrameHeader() (FrameHeader, error) {
|
||||
fr.errDetail = nil
|
||||
if fr.lastFrame != nil {
|
||||
fr.lastFrame.invalidate()
|
||||
}
|
||||
fh, err := readFrameHeader(fr.headerBuf[:], fr.r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return fh, err
|
||||
}
|
||||
if fh.Length > fr.maxReadSize {
|
||||
if fh == invalidHTTP1LookingFrameHeader() {
|
||||
return nil, fmt.Errorf("http2: failed reading the frame payload: %w, note that the frame header looked like an HTTP/1.1 header", ErrFrameTooLarge)
|
||||
return fh, fmt.Errorf("http2: failed reading the frame payload: %w, note that the frame header looked like an HTTP/1.1 header", ErrFrameTooLarge)
|
||||
}
|
||||
return nil, ErrFrameTooLarge
|
||||
return fh, ErrFrameTooLarge
|
||||
}
|
||||
if err := fr.checkFrameOrder(fh); err != nil {
|
||||
return fh, err
|
||||
}
|
||||
return fh, nil
|
||||
}
|
||||
|
||||
// ReadFrameForHeader reads the payload for the frame with the given FrameHeader.
|
||||
//
|
||||
// It behaves identically to ReadFrame, other than not checking the maximum
|
||||
// frame size.
|
||||
func (fr *Framer) ReadFrameForHeader(fh FrameHeader) (Frame, error) {
|
||||
if fr.lastFrame != nil {
|
||||
fr.lastFrame.invalidate()
|
||||
}
|
||||
payload := fr.getReadBuf(fh.Length)
|
||||
if _, err := io.ReadFull(fr.r, payload); err != nil {
|
||||
@@ -527,9 +548,7 @@ func (fr *Framer) ReadFrame() (Frame, error) {
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if err := fr.checkFrameOrder(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fr.lastFrame = f
|
||||
if fr.logReads {
|
||||
fr.debugReadLoggerf("http2: Framer %p: read %v", fr, summarizeFrame(f))
|
||||
}
|
||||
@@ -539,6 +558,24 @@ func (fr *Framer) ReadFrame() (Frame, error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// ReadFrame reads a single frame. The returned Frame is only valid
|
||||
// until the next call to ReadFrame or ReadFrameBodyForHeader.
|
||||
//
|
||||
// If the frame is larger than previously set with SetMaxReadFrameSize, the
|
||||
// returned error is ErrFrameTooLarge. Other errors may be of type
|
||||
// ConnectionError, StreamError, or anything else from the underlying
|
||||
// reader.
|
||||
//
|
||||
// If ReadFrame returns an error and a non-nil Frame, the Frame's StreamID
|
||||
// indicates the stream responsible for the error.
|
||||
func (fr *Framer) ReadFrame() (Frame, error) {
|
||||
fh, err := fr.ReadFrameHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fr.ReadFrameForHeader(fh)
|
||||
}
|
||||
|
||||
// connError returns ConnectionError(code) but first
|
||||
// stashes away a public reason to the caller can optionally relay it
|
||||
// to the peer before hanging up on them. This might help others debug
|
||||
@@ -551,20 +588,19 @@ func (fr *Framer) connError(code ErrCode, reason string) error {
|
||||
// checkFrameOrder reports an error if f is an invalid frame to return
|
||||
// next from ReadFrame. Mostly it checks whether HEADERS and
|
||||
// CONTINUATION frames are contiguous.
|
||||
func (fr *Framer) checkFrameOrder(f Frame) error {
|
||||
last := fr.lastFrame
|
||||
fr.lastFrame = f
|
||||
func (fr *Framer) checkFrameOrder(fh FrameHeader) error {
|
||||
lastType := fr.lastFrameType
|
||||
fr.lastFrameType = fh.Type
|
||||
if fr.AllowIllegalReads {
|
||||
return nil
|
||||
}
|
||||
|
||||
fh := f.Header()
|
||||
if fr.lastHeaderStream != 0 {
|
||||
if fh.Type != FrameContinuation {
|
||||
return fr.connError(ErrCodeProtocol,
|
||||
fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
|
||||
fh.Type, fh.StreamID,
|
||||
last.Header().Type, fr.lastHeaderStream))
|
||||
lastType, fr.lastHeaderStream))
|
||||
}
|
||||
if fh.StreamID != fr.lastHeaderStream {
|
||||
return fr.connError(ErrCodeProtocol,
|
||||
@@ -1152,16 +1188,41 @@ type PriorityFrame struct {
|
||||
PriorityParam
|
||||
}
|
||||
|
||||
var defaultRFC9218Priority = PriorityParam{
|
||||
incremental: 0,
|
||||
urgency: 3,
|
||||
// defaultRFC9218Priority determines what priority we should use as the default
|
||||
// value.
|
||||
//
|
||||
// According to RFC 9218, by default, streams should be given an urgency of 3
|
||||
// and should be non-incremental. However, making streams non-incremental by
|
||||
// default would be a huge change to our historical behavior where we would
|
||||
// round-robin writes across streams. When streams are non-incremental, we
|
||||
// would process streams of the same urgency one-by-one to completion instead.
|
||||
//
|
||||
// To avoid such a sudden change which might break some HTTP/2 users, this
|
||||
// function allows the caller to specify whether they can actually use the
|
||||
// default value as specified in RFC 9218. If not, this function will return a
|
||||
// priority value where streams are incremental by default instead: effectively
|
||||
// a round-robin between stream of the same urgency.
|
||||
//
|
||||
// As an example, a server might not be able to use the RFC 9218 default value
|
||||
// when it's not sure that the client it is serving is aware of RFC 9218.
|
||||
func defaultRFC9218Priority(canUseDefault bool) PriorityParam {
|
||||
if canUseDefault {
|
||||
return PriorityParam{
|
||||
urgency: 3,
|
||||
incremental: 0,
|
||||
}
|
||||
}
|
||||
return PriorityParam{
|
||||
urgency: 3,
|
||||
incremental: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// Note that HTTP/2 has had two different prioritization schemes, and
|
||||
// PriorityParam struct below is a superset of both schemes. The exported
|
||||
// symbols are from RFC 7540 and the non-exported ones are from RFC 9218.
|
||||
|
||||
// PriorityParam are the stream prioritzation parameters.
|
||||
// PriorityParam are the stream prioritization parameters.
|
||||
type PriorityParam struct {
|
||||
// StreamDep is a 31-bit stream identifier for the
|
||||
// stream that this stream depends on. Zero means no
|
||||
@@ -1238,6 +1299,74 @@ func (f *Framer) WritePriority(streamID uint32, p PriorityParam) error {
|
||||
return f.endWrite()
|
||||
}
|
||||
|
||||
// PriorityUpdateFrame is a PRIORITY_UPDATE frame as described in
|
||||
// https://www.rfc-editor.org/rfc/rfc9218.html#name-the-priority_update-frame.
|
||||
type PriorityUpdateFrame struct {
|
||||
FrameHeader
|
||||
Priority string
|
||||
PrioritizedStreamID uint32
|
||||
}
|
||||
|
||||
func parseRFC9218Priority(s string, canUseDefault bool) (p PriorityParam, ok bool) {
|
||||
p = defaultRFC9218Priority(canUseDefault)
|
||||
ok = httpsfv.ParseDictionary(s, func(key, val, _ string) {
|
||||
switch key {
|
||||
case "u":
|
||||
if u, ok := httpsfv.ParseInteger(val); ok && u >= 0 && u <= 7 {
|
||||
p.urgency = uint8(u)
|
||||
}
|
||||
case "i":
|
||||
if i, ok := httpsfv.ParseBoolean(val); ok {
|
||||
if i {
|
||||
p.incremental = 1
|
||||
} else {
|
||||
p.incremental = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
if !ok {
|
||||
return defaultRFC9218Priority(canUseDefault), ok
|
||||
}
|
||||
return p, true
|
||||
}
|
||||
|
||||
func parsePriorityUpdateFrame(_ *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error) {
|
||||
if fh.StreamID != 0 {
|
||||
countError("frame_priority_update_non_zero_stream")
|
||||
return nil, connError{ErrCodeProtocol, "PRIORITY_UPDATE frame with non-zero stream ID"}
|
||||
}
|
||||
if len(payload) < 4 {
|
||||
countError("frame_priority_update_bad_length")
|
||||
return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY_UPDATE frame payload size was %d; want at least 4", len(payload))}
|
||||
}
|
||||
v := binary.BigEndian.Uint32(payload[:4])
|
||||
streamID := v & 0x7fffffff // mask off high bit
|
||||
if streamID == 0 {
|
||||
countError("frame_priority_update_prioritizing_zero_stream")
|
||||
return nil, connError{ErrCodeProtocol, "PRIORITY_UPDATE frame with prioritized stream ID of zero"}
|
||||
}
|
||||
return &PriorityUpdateFrame{
|
||||
FrameHeader: fh,
|
||||
PrioritizedStreamID: streamID,
|
||||
Priority: string(payload[4:]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WritePriorityUpdate writes a PRIORITY_UPDATE frame.
|
||||
//
|
||||
// It will perform exactly one Write to the underlying Writer.
|
||||
// It is the caller's responsibility to not call other Write methods concurrently.
|
||||
func (f *Framer) WritePriorityUpdate(streamID uint32, priority string) error {
|
||||
if !validStreamID(streamID) && !f.AllowIllegalWrites {
|
||||
return errStreamID
|
||||
}
|
||||
f.startWrite(FramePriorityUpdate, 0, 0)
|
||||
f.writeUint32(streamID)
|
||||
f.writeBytes([]byte(priority))
|
||||
return f.endWrite()
|
||||
}
|
||||
|
||||
// A RSTStreamFrame allows for abnormal termination of a stream.
|
||||
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.4
|
||||
type RSTStreamFrame struct {
|
||||
@@ -1519,6 +1648,23 @@ func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
|
||||
return mh.Fields
|
||||
}
|
||||
|
||||
func (mh *MetaHeadersFrame) rfc9218Priority(priorityAware bool) (p PriorityParam, priorityAwareAfter, hasIntermediary bool) {
|
||||
var s string
|
||||
for _, field := range mh.Fields {
|
||||
if field.Name == "priority" {
|
||||
s = field.Value
|
||||
priorityAware = true
|
||||
}
|
||||
if slices.Contains([]string{"via", "forwarded", "x-forwarded-for"}, field.Name) {
|
||||
hasIntermediary = true
|
||||
}
|
||||
}
|
||||
// No need to check for ok. parseRFC9218Priority will return a default
|
||||
// value if there is no priority field or if the field cannot be parsed.
|
||||
p, _ = parseRFC9218Priority(s, priorityAware && !hasIntermediary)
|
||||
return p, priorityAware, hasIntermediary
|
||||
}
|
||||
|
||||
func (mh *MetaHeadersFrame) checkPseudos() error {
|
||||
var isRequest, isResponse bool
|
||||
pf := mh.PseudoFields()
|
||||
|
||||
+2
@@ -169,6 +169,7 @@ const (
|
||||
SettingMaxFrameSize SettingID = 0x5
|
||||
SettingMaxHeaderListSize SettingID = 0x6
|
||||
SettingEnableConnectProtocol SettingID = 0x8
|
||||
SettingNoRFC7540Priorities SettingID = 0x9
|
||||
)
|
||||
|
||||
var settingName = map[SettingID]string{
|
||||
@@ -179,6 +180,7 @@ var settingName = map[SettingID]string{
|
||||
SettingMaxFrameSize: "MAX_FRAME_SIZE",
|
||||
SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
|
||||
SettingEnableConnectProtocol: "ENABLE_CONNECT_PROTOCOL",
|
||||
SettingNoRFC7540Priorities: "NO_RFC7540_PRIORITIES",
|
||||
}
|
||||
|
||||
func (s SettingID) String() string {
|
||||
|
||||
+78
-8
@@ -472,10 +472,13 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon
|
||||
sc.conn.SetWriteDeadline(time.Time{})
|
||||
}
|
||||
|
||||
if s.NewWriteScheduler != nil {
|
||||
switch {
|
||||
case s.NewWriteScheduler != nil:
|
||||
sc.writeSched = s.NewWriteScheduler()
|
||||
} else {
|
||||
case clientPriorityDisabled(http1srv):
|
||||
sc.writeSched = newRoundRobinWriteScheduler()
|
||||
default:
|
||||
sc.writeSched = newPriorityWriteSchedulerRFC9218()
|
||||
}
|
||||
|
||||
// These start at the RFC-specified defaults. If there is a higher
|
||||
@@ -648,6 +651,23 @@ type serverConn struct {
|
||||
|
||||
// Used by startGracefulShutdown.
|
||||
shutdownOnce sync.Once
|
||||
|
||||
// Used for RFC 9218 prioritization.
|
||||
hasIntermediary bool // connection is done via an intermediary / proxy
|
||||
priorityAware bool // the client has sent priority signal, meaning that it is aware of it.
|
||||
}
|
||||
|
||||
func (sc *serverConn) writeSchedIgnoresRFC7540() bool {
|
||||
switch sc.writeSched.(type) {
|
||||
case *priorityWriteSchedulerRFC9218:
|
||||
return true
|
||||
case *randomWriteScheduler:
|
||||
return true
|
||||
case *roundRobinWriteScheduler:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *serverConn) maxHeaderListSize() uint32 {
|
||||
@@ -938,6 +958,9 @@ func (sc *serverConn) serve(conf http2Config) {
|
||||
if !disableExtendedConnectProtocol {
|
||||
settings = append(settings, Setting{SettingEnableConnectProtocol, 1})
|
||||
}
|
||||
if sc.writeSchedIgnoresRFC7540() {
|
||||
settings = append(settings, Setting{SettingNoRFC7540Priorities, 1})
|
||||
}
|
||||
sc.writeFrame(FrameWriteRequest{
|
||||
write: settings,
|
||||
})
|
||||
@@ -1623,6 +1646,8 @@ func (sc *serverConn) processFrame(f Frame) error {
|
||||
// A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE
|
||||
// frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
|
||||
return sc.countError("push_promise", ConnectionError(ErrCodeProtocol))
|
||||
case *PriorityUpdateFrame:
|
||||
return sc.processPriorityUpdate(f)
|
||||
default:
|
||||
sc.vlogf("http2: server ignoring frame: %v", f.Header())
|
||||
return nil
|
||||
@@ -1803,6 +1828,10 @@ func (sc *serverConn) processSetting(s Setting) error {
|
||||
case SettingEnableConnectProtocol:
|
||||
// Receipt of this parameter by a server does not
|
||||
// have any impact
|
||||
case SettingNoRFC7540Priorities:
|
||||
if s.Val > 1 {
|
||||
return ConnectionError(ErrCodeProtocol)
|
||||
}
|
||||
default:
|
||||
// Unknown setting: "An endpoint that receives a SETTINGS
|
||||
// frame with any unknown or unsupported identifier MUST
|
||||
@@ -2073,13 +2102,33 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
|
||||
if f.StreamEnded() {
|
||||
initialState = stateHalfClosedRemote
|
||||
}
|
||||
st := sc.newStream(id, 0, initialState)
|
||||
|
||||
// We are handling two special cases here:
|
||||
// 1. When a request is sent via an intermediary, we force priority to be
|
||||
// u=3,i. This is essentially a round-robin behavior, and is done to ensure
|
||||
// fairness between, for example, multiple clients using the same proxy.
|
||||
// 2. Until a client has shown that it is aware of RFC 9218, we make its
|
||||
// streams non-incremental by default. This is done to preserve the
|
||||
// historical behavior of handling streams in a round-robin manner, rather
|
||||
// than one-by-one to completion.
|
||||
initialPriority := defaultRFC9218Priority(sc.priorityAware && !sc.hasIntermediary)
|
||||
if _, ok := sc.writeSched.(*priorityWriteSchedulerRFC9218); ok && !sc.hasIntermediary {
|
||||
headerPriority, priorityAware, hasIntermediary := f.rfc9218Priority(sc.priorityAware)
|
||||
initialPriority = headerPriority
|
||||
sc.hasIntermediary = hasIntermediary
|
||||
if priorityAware {
|
||||
sc.priorityAware = true
|
||||
}
|
||||
}
|
||||
st := sc.newStream(id, 0, initialState, initialPriority)
|
||||
|
||||
if f.HasPriority() {
|
||||
if err := sc.checkPriority(f.StreamID, f.Priority); err != nil {
|
||||
return err
|
||||
}
|
||||
sc.writeSched.AdjustStream(st.id, f.Priority)
|
||||
if !sc.writeSchedIgnoresRFC7540() {
|
||||
sc.writeSched.AdjustStream(st.id, f.Priority)
|
||||
}
|
||||
}
|
||||
|
||||
rw, req, err := sc.newWriterAndRequest(st, f)
|
||||
@@ -2120,7 +2169,7 @@ func (sc *serverConn) upgradeRequest(req *http.Request) {
|
||||
sc.serveG.check()
|
||||
id := uint32(1)
|
||||
sc.maxClientStreamID = id
|
||||
st := sc.newStream(id, 0, stateHalfClosedRemote)
|
||||
st := sc.newStream(id, 0, stateHalfClosedRemote, defaultRFC9218Priority(sc.priorityAware && !sc.hasIntermediary))
|
||||
st.reqTrailer = req.Trailer
|
||||
if st.reqTrailer != nil {
|
||||
st.trailer = make(http.Header)
|
||||
@@ -2185,11 +2234,32 @@ func (sc *serverConn) processPriority(f *PriorityFrame) error {
|
||||
if err := sc.checkPriority(f.StreamID, f.PriorityParam); err != nil {
|
||||
return err
|
||||
}
|
||||
// We need to avoid calling AdjustStream when using the RFC 9218 write
|
||||
// scheduler. Otherwise, incremental's zero value in PriorityParam will
|
||||
// unexpectedly make all streams non-incremental. This causes us to process
|
||||
// streams one-by-one to completion rather than doing it in a round-robin
|
||||
// manner (the historical behavior), which might be unexpected to users.
|
||||
if sc.writeSchedIgnoresRFC7540() {
|
||||
return nil
|
||||
}
|
||||
sc.writeSched.AdjustStream(f.StreamID, f.PriorityParam)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream {
|
||||
func (sc *serverConn) processPriorityUpdate(f *PriorityUpdateFrame) error {
|
||||
sc.priorityAware = true
|
||||
if _, ok := sc.writeSched.(*priorityWriteSchedulerRFC9218); !ok {
|
||||
return nil
|
||||
}
|
||||
p, ok := parseRFC9218Priority(f.Priority, sc.priorityAware)
|
||||
if !ok {
|
||||
return sc.countError("unparsable_priority_update", streamError(f.PrioritizedStreamID, ErrCodeProtocol))
|
||||
}
|
||||
sc.writeSched.AdjustStream(f.PrioritizedStreamID, p)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sc *serverConn) newStream(id, pusherID uint32, state streamState, priority PriorityParam) *stream {
|
||||
sc.serveG.check()
|
||||
if id == 0 {
|
||||
panic("internal error: cannot create stream with id 0")
|
||||
@@ -2212,7 +2282,7 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream
|
||||
}
|
||||
|
||||
sc.streams[id] = st
|
||||
sc.writeSched.OpenStream(st.id, OpenStreamOptions{PusherID: pusherID})
|
||||
sc.writeSched.OpenStream(st.id, OpenStreamOptions{PusherID: pusherID, priority: priority})
|
||||
if st.isPushed() {
|
||||
sc.curPushedStreams++
|
||||
} else {
|
||||
@@ -3218,7 +3288,7 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
|
||||
// transition to "half closed (remote)" after sending the initial HEADERS, but
|
||||
// we start in "half closed (remote)" for simplicity.
|
||||
// See further comments at the definition of stateHalfClosedRemote.
|
||||
promised := sc.newStream(promisedID, msg.parent.id, stateHalfClosedRemote)
|
||||
promised := sc.newStream(promisedID, msg.parent.id, stateHalfClosedRemote, defaultRFC9218Priority(sc.priorityAware && !sc.hasIntermediary))
|
||||
rw, req, err := sc.newWriterAndRequestNoBody(promised, httpcommon.ServerRequestParam{
|
||||
Method: msg.method,
|
||||
Scheme: msg.url.Scheme,
|
||||
|
||||
+240
-31
@@ -9,6 +9,7 @@ package http2
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
@@ -375,11 +376,24 @@ type ClientConn struct {
|
||||
// completely unresponsive connection.
|
||||
pendingResets int
|
||||
|
||||
// readBeforeStreamID is the smallest stream ID that has not been followed by
|
||||
// a frame read from the peer. We use this to determine when a request may
|
||||
// have been sent to a completely unresponsive connection:
|
||||
// If the request ID is less than readBeforeStreamID, then we have had some
|
||||
// indication of life on the connection since sending the request.
|
||||
readBeforeStreamID uint32
|
||||
|
||||
// reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.
|
||||
// Write to reqHeaderMu to lock it, read from it to unlock.
|
||||
// Lock reqmu BEFORE mu or wmu.
|
||||
reqHeaderMu chan struct{}
|
||||
|
||||
// internalStateHook reports state changes back to the net/http.ClientConn.
|
||||
// Note that this is different from the user state hook registered by
|
||||
// net/http.ClientConn.SetStateHook: The internal hook calls ClientConn,
|
||||
// which calls the user hook.
|
||||
internalStateHook func()
|
||||
|
||||
// wmu is held while writing.
|
||||
// Acquire BEFORE mu when holding both, to avoid blocking mu on network writes.
|
||||
// Only acquire both at the same time when changing peer settings.
|
||||
@@ -709,7 +723,7 @@ func canRetryError(err error) bool {
|
||||
|
||||
func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {
|
||||
if t.transportTestHooks != nil {
|
||||
return t.newClientConn(nil, singleUse)
|
||||
return t.newClientConn(nil, singleUse, nil)
|
||||
}
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
@@ -719,7 +733,7 @@ func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse b
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.newClientConn(tconn, singleUse)
|
||||
return t.newClientConn(tconn, singleUse, nil)
|
||||
}
|
||||
|
||||
func (t *Transport) newTLSConfig(host string) *tls.Config {
|
||||
@@ -771,10 +785,10 @@ func (t *Transport) expectContinueTimeout() time.Duration {
|
||||
}
|
||||
|
||||
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||
return t.newClientConn(c, t.disableKeepAlives())
|
||||
return t.newClientConn(c, t.disableKeepAlives(), nil)
|
||||
}
|
||||
|
||||
func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) {
|
||||
func (t *Transport) newClientConn(c net.Conn, singleUse bool, internalStateHook func()) (*ClientConn, error) {
|
||||
conf := configFromTransport(t)
|
||||
cc := &ClientConn{
|
||||
t: t,
|
||||
@@ -796,6 +810,7 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
|
||||
pings: make(map[[8]byte]chan struct{}),
|
||||
reqHeaderMu: make(chan struct{}, 1),
|
||||
lastActive: time.Now(),
|
||||
internalStateHook: internalStateHook,
|
||||
}
|
||||
if t.transportTestHooks != nil {
|
||||
t.transportTestHooks.newclientconn(cc)
|
||||
@@ -1036,10 +1051,7 @@ func (cc *ClientConn) idleStateLocked() (st clientConnIdleState) {
|
||||
maxConcurrentOkay = cc.currentRequestCountLocked() < int(cc.maxConcurrentStreams)
|
||||
}
|
||||
|
||||
st.canTakeNewRequest = cc.goAway == nil && !cc.closed && !cc.closing && maxConcurrentOkay &&
|
||||
!cc.doNotReuse &&
|
||||
int64(cc.nextStreamID)+2*int64(cc.pendingRequests) < math.MaxInt32 &&
|
||||
!cc.tooIdleLocked()
|
||||
st.canTakeNewRequest = maxConcurrentOkay && cc.isUsableLocked()
|
||||
|
||||
// If this connection has never been used for a request and is closed,
|
||||
// then let it take a request (which will fail).
|
||||
@@ -1055,6 +1067,31 @@ func (cc *ClientConn) idleStateLocked() (st clientConnIdleState) {
|
||||
return
|
||||
}
|
||||
|
||||
func (cc *ClientConn) isUsableLocked() bool {
|
||||
return cc.goAway == nil &&
|
||||
!cc.closed &&
|
||||
!cc.closing &&
|
||||
!cc.doNotReuse &&
|
||||
int64(cc.nextStreamID)+2*int64(cc.pendingRequests) < math.MaxInt32 &&
|
||||
!cc.tooIdleLocked()
|
||||
}
|
||||
|
||||
// canReserveLocked reports whether a net/http.ClientConn can reserve a slot on this conn.
|
||||
//
|
||||
// This follows slightly different rules than clientConnIdleState.canTakeNewRequest.
|
||||
// We only permit reservations up to the conn's concurrency limit.
|
||||
// This differs from ClientConn.ReserveNewRequest, which permits reservations
|
||||
// past the limit when StrictMaxConcurrentStreams is set.
|
||||
func (cc *ClientConn) canReserveLocked() bool {
|
||||
if cc.currentRequestCountLocked() >= int(cc.maxConcurrentStreams) {
|
||||
return false
|
||||
}
|
||||
if !cc.isUsableLocked() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// currentRequestCountLocked reports the number of concurrency slots currently in use,
|
||||
// including active streams, reserved slots, and reset streams waiting for acknowledgement.
|
||||
func (cc *ClientConn) currentRequestCountLocked() int {
|
||||
@@ -1066,6 +1103,14 @@ func (cc *ClientConn) canTakeNewRequestLocked() bool {
|
||||
return st.canTakeNewRequest
|
||||
}
|
||||
|
||||
// availableLocked reports the number of concurrency slots available.
|
||||
func (cc *ClientConn) availableLocked() int {
|
||||
if !cc.canTakeNewRequestLocked() {
|
||||
return 0
|
||||
}
|
||||
return max(0, int(cc.maxConcurrentStreams)-cc.currentRequestCountLocked())
|
||||
}
|
||||
|
||||
// tooIdleLocked reports whether this connection has been been sitting idle
|
||||
// for too much wall time.
|
||||
func (cc *ClientConn) tooIdleLocked() bool {
|
||||
@@ -1090,6 +1135,7 @@ func (cc *ClientConn) closeConn() {
|
||||
t := time.AfterFunc(250*time.Millisecond, cc.forceCloseConn)
|
||||
defer t.Stop()
|
||||
cc.tconn.Close()
|
||||
cc.maybeCallStateHook()
|
||||
}
|
||||
|
||||
// A tls.Conn.Close can hang for a long time if the peer is unresponsive.
|
||||
@@ -1615,6 +1661,8 @@ func (cs *clientStream) cleanupWriteRequest(err error) {
|
||||
}
|
||||
bodyClosed := cs.reqBodyClosed
|
||||
closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() || cc.goAway != nil
|
||||
// Have we read any frames from the connection since sending this request?
|
||||
readSinceStream := cc.readBeforeStreamID > cs.ID
|
||||
cc.mu.Unlock()
|
||||
if mustCloseBody {
|
||||
cs.reqBody.Close()
|
||||
@@ -1646,8 +1694,10 @@ func (cs *clientStream) cleanupWriteRequest(err error) {
|
||||
//
|
||||
// This could be due to the server becoming unresponsive.
|
||||
// To avoid sending too many requests on a dead connection,
|
||||
// we let the request continue to consume a concurrency slot
|
||||
// until we can confirm the server is still responding.
|
||||
// if we haven't read any frames from the connection since
|
||||
// sending this request, we let it continue to consume
|
||||
// a concurrency slot until we can confirm the server is
|
||||
// still responding.
|
||||
// We do this by sending a PING frame along with the RST_STREAM
|
||||
// (unless a ping is already in flight).
|
||||
//
|
||||
@@ -1658,7 +1708,7 @@ func (cs *clientStream) cleanupWriteRequest(err error) {
|
||||
// because it's short lived and will probably be closed before
|
||||
// we get the ping response.
|
||||
ping := false
|
||||
if !closeOnIdle {
|
||||
if !closeOnIdle && !readSinceStream {
|
||||
cc.mu.Lock()
|
||||
// rstStreamPingsBlocked works around a gRPC behavior:
|
||||
// see comment on the field for details.
|
||||
@@ -1692,6 +1742,7 @@ func (cs *clientStream) cleanupWriteRequest(err error) {
|
||||
}
|
||||
|
||||
close(cs.donec)
|
||||
cc.maybeCallStateHook()
|
||||
}
|
||||
|
||||
// awaitOpenSlotForStreamLocked waits until len(streams) < maxConcurrentStreams.
|
||||
@@ -2728,6 +2779,11 @@ func (rl *clientConnReadLoop) endStreamError(cs *clientStream, err error) {
|
||||
cs.abortStream(err)
|
||||
}
|
||||
|
||||
func (rl *clientConnReadLoop) endStreamErrorLocked(cs *clientStream, err error) {
|
||||
cs.readAborted = true
|
||||
cs.abortStreamLocked(err)
|
||||
}
|
||||
|
||||
// Constants passed to streamByID for documentation purposes.
|
||||
const (
|
||||
headerOrDataFrame = true
|
||||
@@ -2744,6 +2800,7 @@ func (rl *clientConnReadLoop) streamByID(id uint32, headerOrData bool) *clientSt
|
||||
// See comment on ClientConn.rstStreamPingsBlocked for details.
|
||||
rl.cc.rstStreamPingsBlocked = false
|
||||
}
|
||||
rl.cc.readBeforeStreamID = rl.cc.nextStreamID
|
||||
cs := rl.cc.streams[id]
|
||||
if cs != nil && !cs.readAborted {
|
||||
return cs
|
||||
@@ -2794,6 +2851,7 @@ func (rl *clientConnReadLoop) processSettings(f *SettingsFrame) error {
|
||||
|
||||
func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
|
||||
cc := rl.cc
|
||||
defer cc.maybeCallStateHook()
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
|
||||
@@ -2893,7 +2951,7 @@ func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error {
|
||||
if !fl.add(int32(f.Increment)) {
|
||||
// For stream, the sender sends RST_STREAM with an error code of FLOW_CONTROL_ERROR
|
||||
if cs != nil {
|
||||
rl.endStreamError(cs, StreamError{
|
||||
rl.endStreamErrorLocked(cs, StreamError{
|
||||
StreamID: f.StreamID,
|
||||
Code: ErrCodeFlowControl,
|
||||
})
|
||||
@@ -2974,6 +3032,7 @@ func (cc *ClientConn) Ping(ctx context.Context) error {
|
||||
func (rl *clientConnReadLoop) processPing(f *PingFrame) error {
|
||||
if f.IsAck() {
|
||||
cc := rl.cc
|
||||
defer cc.maybeCallStateHook()
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
// If ack, notify listener if any
|
||||
@@ -3076,35 +3135,102 @@ type erringRoundTripper struct{ err error }
|
||||
func (rt erringRoundTripper) RoundTripErr() error { return rt.err }
|
||||
func (rt erringRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, rt.err }
|
||||
|
||||
var errConcurrentReadOnResBody = errors.New("http2: concurrent read on response body")
|
||||
|
||||
// gzipReader wraps a response body so it can lazily
|
||||
// call gzip.NewReader on the first call to Read
|
||||
// get gzip.Reader from the pool on the first call to Read.
|
||||
// After Close is called it puts gzip.Reader to the pool immediately
|
||||
// if there is no Read in progress or later when Read completes.
|
||||
type gzipReader struct {
|
||||
_ incomparable
|
||||
body io.ReadCloser // underlying Response.Body
|
||||
zr *gzip.Reader // lazily-initialized gzip reader
|
||||
zerr error // sticky error
|
||||
mu sync.Mutex // guards zr and zerr
|
||||
zr *gzip.Reader // stores gzip reader from the pool between reads
|
||||
zerr error // sticky gzip reader init error or sentinel value to detect concurrent read and read after close
|
||||
}
|
||||
|
||||
type eofReader struct{}
|
||||
|
||||
func (eofReader) Read([]byte) (int, error) { return 0, io.EOF }
|
||||
func (eofReader) ReadByte() (byte, error) { return 0, io.EOF }
|
||||
|
||||
var gzipPool = sync.Pool{New: func() any { return new(gzip.Reader) }}
|
||||
|
||||
// gzipPoolGet gets a gzip.Reader from the pool and resets it to read from r.
|
||||
func gzipPoolGet(r io.Reader) (*gzip.Reader, error) {
|
||||
zr := gzipPool.Get().(*gzip.Reader)
|
||||
if err := zr.Reset(r); err != nil {
|
||||
gzipPoolPut(zr)
|
||||
return nil, err
|
||||
}
|
||||
return zr, nil
|
||||
}
|
||||
|
||||
// gzipPoolPut puts a gzip.Reader back into the pool.
|
||||
func gzipPoolPut(zr *gzip.Reader) {
|
||||
// Reset will allocate bufio.Reader if we pass it anything
|
||||
// other than a flate.Reader, so ensure that it's getting one.
|
||||
var r flate.Reader = eofReader{}
|
||||
zr.Reset(r)
|
||||
gzipPool.Put(zr)
|
||||
}
|
||||
|
||||
// acquire returns a gzip.Reader for reading response body.
|
||||
// The reader must be released after use.
|
||||
func (gz *gzipReader) acquire() (*gzip.Reader, error) {
|
||||
gz.mu.Lock()
|
||||
defer gz.mu.Unlock()
|
||||
if gz.zerr != nil {
|
||||
return nil, gz.zerr
|
||||
}
|
||||
if gz.zr == nil {
|
||||
gz.zr, gz.zerr = gzipPoolGet(gz.body)
|
||||
if gz.zerr != nil {
|
||||
return nil, gz.zerr
|
||||
}
|
||||
}
|
||||
ret := gz.zr
|
||||
gz.zr, gz.zerr = nil, errConcurrentReadOnResBody
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// release returns the gzip.Reader to the pool if Close was called during Read.
|
||||
func (gz *gzipReader) release(zr *gzip.Reader) {
|
||||
gz.mu.Lock()
|
||||
defer gz.mu.Unlock()
|
||||
if gz.zerr == errConcurrentReadOnResBody {
|
||||
gz.zr, gz.zerr = zr, nil
|
||||
} else { // fs.ErrClosed
|
||||
gzipPoolPut(zr)
|
||||
}
|
||||
}
|
||||
|
||||
// close returns the gzip.Reader to the pool immediately or
|
||||
// signals release to do so after Read completes.
|
||||
func (gz *gzipReader) close() {
|
||||
gz.mu.Lock()
|
||||
defer gz.mu.Unlock()
|
||||
if gz.zerr == nil && gz.zr != nil {
|
||||
gzipPoolPut(gz.zr)
|
||||
gz.zr = nil
|
||||
}
|
||||
gz.zerr = fs.ErrClosed
|
||||
}
|
||||
|
||||
func (gz *gzipReader) Read(p []byte) (n int, err error) {
|
||||
if gz.zerr != nil {
|
||||
return 0, gz.zerr
|
||||
zr, err := gz.acquire()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if gz.zr == nil {
|
||||
gz.zr, err = gzip.NewReader(gz.body)
|
||||
if err != nil {
|
||||
gz.zerr = err
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return gz.zr.Read(p)
|
||||
defer gz.release(zr)
|
||||
|
||||
return zr.Read(p)
|
||||
}
|
||||
|
||||
func (gz *gzipReader) Close() error {
|
||||
if err := gz.body.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
gz.zerr = fs.ErrClosed
|
||||
return nil
|
||||
gz.close()
|
||||
|
||||
return gz.body.Close()
|
||||
}
|
||||
|
||||
type errorReader struct{ err error }
|
||||
@@ -3130,9 +3256,13 @@ func registerHTTPSProtocol(t *http.Transport, rt noDialH2RoundTripper) (err erro
|
||||
}
|
||||
|
||||
// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
|
||||
// if there's already has a cached connection to the host.
|
||||
// if there's already a cached connection to the host.
|
||||
// (The field is exported so it can be accessed via reflect from net/http; tested
|
||||
// by TestNoDialH2RoundTripperType)
|
||||
//
|
||||
// A noDialH2RoundTripper is registered with http1.Transport.RegisterProtocol,
|
||||
// and the http1.Transport can use type assertions to call non-RoundTrip methods on it.
|
||||
// This lets us expose, for example, NewClientConn to net/http.
|
||||
type noDialH2RoundTripper struct{ *Transport }
|
||||
|
||||
func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
@@ -3143,6 +3273,85 @@ func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, err
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (rt noDialH2RoundTripper) NewClientConn(conn net.Conn, internalStateHook func()) (http.RoundTripper, error) {
|
||||
tr := rt.Transport
|
||||
cc, err := tr.newClientConn(conn, tr.disableKeepAlives(), internalStateHook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// RoundTrip should block when the conn is at its concurrency limit,
|
||||
// not return an error. Setting strictMaxConcurrentStreams enables this.
|
||||
cc.strictMaxConcurrentStreams = true
|
||||
|
||||
return netHTTPClientConn{cc}, nil
|
||||
}
|
||||
|
||||
// netHTTPClientConn wraps ClientConn and implements the interface net/http expects from
|
||||
// the RoundTripper returned by NewClientConn.
|
||||
type netHTTPClientConn struct {
|
||||
cc *ClientConn
|
||||
}
|
||||
|
||||
func (cc netHTTPClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return cc.cc.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (cc netHTTPClientConn) Close() error {
|
||||
return cc.cc.Close()
|
||||
}
|
||||
|
||||
func (cc netHTTPClientConn) Err() error {
|
||||
cc.cc.mu.Lock()
|
||||
defer cc.cc.mu.Unlock()
|
||||
if cc.cc.closed {
|
||||
return errors.New("connection closed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cc netHTTPClientConn) Reserve() error {
|
||||
defer cc.cc.maybeCallStateHook()
|
||||
cc.cc.mu.Lock()
|
||||
defer cc.cc.mu.Unlock()
|
||||
if !cc.cc.canReserveLocked() {
|
||||
return errors.New("connection is unavailable")
|
||||
}
|
||||
cc.cc.streamsReserved++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cc netHTTPClientConn) Release() {
|
||||
defer cc.cc.maybeCallStateHook()
|
||||
cc.cc.mu.Lock()
|
||||
defer cc.cc.mu.Unlock()
|
||||
// We don't complain if streamsReserved is 0.
|
||||
//
|
||||
// This is consistent with RoundTrip: both Release and RoundTrip will
|
||||
// consume a reservation iff one exists.
|
||||
if cc.cc.streamsReserved > 0 {
|
||||
cc.cc.streamsReserved--
|
||||
}
|
||||
}
|
||||
|
||||
func (cc netHTTPClientConn) Available() int {
|
||||
cc.cc.mu.Lock()
|
||||
defer cc.cc.mu.Unlock()
|
||||
return cc.cc.availableLocked()
|
||||
}
|
||||
|
||||
func (cc netHTTPClientConn) InFlight() int {
|
||||
cc.cc.mu.Lock()
|
||||
defer cc.cc.mu.Unlock()
|
||||
return cc.cc.currentRequestCountLocked()
|
||||
}
|
||||
|
||||
func (cc *ClientConn) maybeCallStateHook() {
|
||||
if cc.internalStateHook != nil {
|
||||
cc.internalStateHook()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) idleConnTimeout() time.Duration {
|
||||
// to keep things backwards compatible, we use non-zero values of
|
||||
// IdleConnTimeout, followed by using the IdleConnTimeout on the underlying
|
||||
|
||||
+50
-15
@@ -185,45 +185,75 @@ func (wr *FrameWriteRequest) replyToWriter(err error) {
|
||||
}
|
||||
|
||||
// writeQueue is used by implementations of WriteScheduler.
|
||||
//
|
||||
// Each writeQueue contains a queue of FrameWriteRequests, meant to store all
|
||||
// FrameWriteRequests associated with a given stream. This is implemented as a
|
||||
// two-stage queue: currQueue[currPos:] and nextQueue. Removing an item is done
|
||||
// by incrementing currPos of currQueue. Adding an item is done by appending it
|
||||
// to the nextQueue. If currQueue is empty when trying to remove an item, we
|
||||
// can swap currQueue and nextQueue to remedy the situation.
|
||||
// This two-stage queue is analogous to the use of two lists in Okasaki's
|
||||
// purely functional queue but without the overhead of reversing the list when
|
||||
// swapping stages.
|
||||
//
|
||||
// writeQueue also contains prev and next, this can be used by implementations
|
||||
// of WriteScheduler to construct data structures that represent the order of
|
||||
// writing between different streams (e.g. circular linked list).
|
||||
type writeQueue struct {
|
||||
s []FrameWriteRequest
|
||||
currQueue []FrameWriteRequest
|
||||
nextQueue []FrameWriteRequest
|
||||
currPos int
|
||||
|
||||
prev, next *writeQueue
|
||||
}
|
||||
|
||||
func (q *writeQueue) empty() bool { return len(q.s) == 0 }
|
||||
func (q *writeQueue) empty() bool {
|
||||
return (len(q.currQueue) - q.currPos + len(q.nextQueue)) == 0
|
||||
}
|
||||
|
||||
func (q *writeQueue) push(wr FrameWriteRequest) {
|
||||
q.s = append(q.s, wr)
|
||||
q.nextQueue = append(q.nextQueue, wr)
|
||||
}
|
||||
|
||||
func (q *writeQueue) shift() FrameWriteRequest {
|
||||
if len(q.s) == 0 {
|
||||
if q.empty() {
|
||||
panic("invalid use of queue")
|
||||
}
|
||||
wr := q.s[0]
|
||||
// TODO: less copy-happy queue.
|
||||
copy(q.s, q.s[1:])
|
||||
q.s[len(q.s)-1] = FrameWriteRequest{}
|
||||
q.s = q.s[:len(q.s)-1]
|
||||
if q.currPos >= len(q.currQueue) {
|
||||
q.currQueue, q.currPos, q.nextQueue = q.nextQueue, 0, q.currQueue[:0]
|
||||
}
|
||||
wr := q.currQueue[q.currPos]
|
||||
q.currQueue[q.currPos] = FrameWriteRequest{}
|
||||
q.currPos++
|
||||
return wr
|
||||
}
|
||||
|
||||
func (q *writeQueue) peek() *FrameWriteRequest {
|
||||
if q.currPos < len(q.currQueue) {
|
||||
return &q.currQueue[q.currPos]
|
||||
}
|
||||
if len(q.nextQueue) > 0 {
|
||||
return &q.nextQueue[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// consume consumes up to n bytes from q.s[0]. If the frame is
|
||||
// entirely consumed, it is removed from the queue. If the frame
|
||||
// is partially consumed, the frame is kept with the consumed
|
||||
// bytes removed. Returns true iff any bytes were consumed.
|
||||
func (q *writeQueue) consume(n int32) (FrameWriteRequest, bool) {
|
||||
if len(q.s) == 0 {
|
||||
if q.empty() {
|
||||
return FrameWriteRequest{}, false
|
||||
}
|
||||
consumed, rest, numresult := q.s[0].Consume(n)
|
||||
consumed, rest, numresult := q.peek().Consume(n)
|
||||
switch numresult {
|
||||
case 0:
|
||||
return FrameWriteRequest{}, false
|
||||
case 1:
|
||||
q.shift()
|
||||
case 2:
|
||||
q.s[0] = rest
|
||||
*q.peek() = rest
|
||||
}
|
||||
return consumed, true
|
||||
}
|
||||
@@ -232,10 +262,15 @@ type writeQueuePool []*writeQueue
|
||||
|
||||
// put inserts an unused writeQueue into the pool.
|
||||
func (p *writeQueuePool) put(q *writeQueue) {
|
||||
for i := range q.s {
|
||||
q.s[i] = FrameWriteRequest{}
|
||||
for i := range q.currQueue {
|
||||
q.currQueue[i] = FrameWriteRequest{}
|
||||
}
|
||||
q.s = q.s[:0]
|
||||
for i := range q.nextQueue {
|
||||
q.nextQueue[i] = FrameWriteRequest{}
|
||||
}
|
||||
q.currQueue = q.currQueue[:0]
|
||||
q.nextQueue = q.nextQueue[:0]
|
||||
q.currPos = 0
|
||||
*p = append(*p, q)
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -56,6 +56,10 @@ type PriorityWriteSchedulerConfig struct {
|
||||
// frames by following HTTP/2 priorities as described in RFC 7540 Section 5.3.
|
||||
// If cfg is nil, default options are used.
|
||||
func NewPriorityWriteScheduler(cfg *PriorityWriteSchedulerConfig) WriteScheduler {
|
||||
return newPriorityWriteSchedulerRFC7540(cfg)
|
||||
}
|
||||
|
||||
func newPriorityWriteSchedulerRFC7540(cfg *PriorityWriteSchedulerConfig) WriteScheduler {
|
||||
if cfg == nil {
|
||||
// For justification of these defaults, see:
|
||||
// https://docs.google.com/document/d/1oLhNg1skaWD4_DtaoCxdSRN5erEXrH-KnLrMwEpOtFY
|
||||
@@ -214,8 +218,8 @@ func (z sortPriorityNodeSiblingsRFC7540) Swap(i, k int) { z[i], z[k] = z[k], z[i
|
||||
func (z sortPriorityNodeSiblingsRFC7540) Less(i, k int) bool {
|
||||
// Prefer the subtree that has sent fewer bytes relative to its weight.
|
||||
// See sections 5.3.2 and 5.3.4.
|
||||
wi, bi := float64(z[i].weight+1), float64(z[i].subtreeBytes)
|
||||
wk, bk := float64(z[k].weight+1), float64(z[k].subtreeBytes)
|
||||
wi, bi := float64(z[i].weight)+1, float64(z[i].subtreeBytes)
|
||||
wk, bk := float64(z[k].weight)+1, float64(z[k].subtreeBytes)
|
||||
if bi == 0 && bk == 0 {
|
||||
return wi >= wk
|
||||
}
|
||||
@@ -302,7 +306,6 @@ func (ws *priorityWriteSchedulerRFC7540) CloseStream(streamID uint32) {
|
||||
|
||||
q := n.q
|
||||
ws.queuePool.put(&q)
|
||||
n.q.s = nil
|
||||
if ws.maxClosedNodesInTree > 0 {
|
||||
ws.addClosedOrIdleNode(&ws.closedNodes, ws.maxClosedNodesInTree, n)
|
||||
} else {
|
||||
|
||||
Generated
Vendored
+16
-1
@@ -37,9 +37,18 @@ type priorityWriteSchedulerRFC9218 struct {
|
||||
// incremental streams or not, when urgency is the same in a given Pop()
|
||||
// call.
|
||||
prioritizeIncremental bool
|
||||
|
||||
// priorityUpdateBuf is used to buffer the most recent PRIORITY_UPDATE we
|
||||
// receive per https://www.rfc-editor.org/rfc/rfc9218.html#name-the-priority_update-frame.
|
||||
priorityUpdateBuf struct {
|
||||
// streamID being 0 means that the buffer is empty. This is a safe
|
||||
// assumption as PRIORITY_UPDATE for stream 0 is a PROTOCOL_ERROR.
|
||||
streamID uint32
|
||||
priority PriorityParam
|
||||
}
|
||||
}
|
||||
|
||||
func newPriorityWriteSchedulerRFC9128() WriteScheduler {
|
||||
func newPriorityWriteSchedulerRFC9218() WriteScheduler {
|
||||
ws := &priorityWriteSchedulerRFC9218{
|
||||
streams: make(map[uint32]streamMetadata),
|
||||
}
|
||||
@@ -50,6 +59,10 @@ func (ws *priorityWriteSchedulerRFC9218) OpenStream(streamID uint32, opt OpenStr
|
||||
if ws.streams[streamID].location != nil {
|
||||
panic(fmt.Errorf("stream %d already opened", streamID))
|
||||
}
|
||||
if streamID == ws.priorityUpdateBuf.streamID {
|
||||
ws.priorityUpdateBuf.streamID = 0
|
||||
opt.priority = ws.priorityUpdateBuf.priority
|
||||
}
|
||||
q := ws.queuePool.get()
|
||||
ws.streams[streamID] = streamMetadata{
|
||||
location: q,
|
||||
@@ -95,6 +108,8 @@ func (ws *priorityWriteSchedulerRFC9218) AdjustStream(streamID uint32, priority
|
||||
metadata := ws.streams[streamID]
|
||||
q, u, i := metadata.location, metadata.priority.urgency, metadata.priority.incremental
|
||||
if q == nil {
|
||||
ws.priorityUpdateBuf.streamID = streamID
|
||||
ws.priorityUpdateBuf.priority = priority
|
||||
return
|
||||
}
|
||||
|
||||
+665
@@ -0,0 +1,665 @@
|
||||
// Copyright 2025 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 httpsfv provides functionality for dealing with HTTP Structured
|
||||
// Field Values.
|
||||
package httpsfv
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func isLCAlpha(b byte) bool {
|
||||
return (b >= 'a' && b <= 'z')
|
||||
}
|
||||
|
||||
func isAlpha(b byte) bool {
|
||||
return isLCAlpha(b) || (b >= 'A' && b <= 'Z')
|
||||
}
|
||||
|
||||
func isDigit(b byte) bool {
|
||||
return b >= '0' && b <= '9'
|
||||
}
|
||||
|
||||
func isVChar(b byte) bool {
|
||||
return b >= 0x21 && b <= 0x7e
|
||||
}
|
||||
|
||||
func isSP(b byte) bool {
|
||||
return b == 0x20
|
||||
}
|
||||
|
||||
func isTChar(b byte) bool {
|
||||
if isAlpha(b) || isDigit(b) {
|
||||
return true
|
||||
}
|
||||
return slices.Contains([]byte{'!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~'}, b)
|
||||
}
|
||||
|
||||
func countLeftWhitespace(s string) int {
|
||||
i := 0
|
||||
for _, ch := range []byte(s) {
|
||||
if ch != ' ' && ch != '\t' {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc4648#section-8.
|
||||
func decOctetHex(ch1, ch2 byte) (ch byte, ok bool) {
|
||||
decBase16 := func(in byte) (out byte, ok bool) {
|
||||
if !isDigit(in) && !(in >= 'a' && in <= 'f') {
|
||||
return 0, false
|
||||
}
|
||||
if isDigit(in) {
|
||||
return in - '0', true
|
||||
}
|
||||
return in - 'a' + 10, true
|
||||
}
|
||||
|
||||
if ch1, ok = decBase16(ch1); !ok {
|
||||
return 0, ok
|
||||
}
|
||||
if ch2, ok = decBase16(ch2); !ok {
|
||||
return 0, ok
|
||||
}
|
||||
return ch1<<4 | ch2, true
|
||||
}
|
||||
|
||||
// ParseList parses a list from a given HTTP Structured Field Values.
|
||||
//
|
||||
// Given an HTTP SFV string that represents a list, it will call the given
|
||||
// function using each of the members and parameters contained in the list.
|
||||
// This allows the caller to extract information out of the list.
|
||||
//
|
||||
// This function will return once it encounters the end of the string, or
|
||||
// something that is not a list. If it cannot consume the entire given
|
||||
// string, the ok value returned will be false.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-list.
|
||||
func ParseList(s string, f func(member, param string)) (ok bool) {
|
||||
for len(s) != 0 {
|
||||
var member, param string
|
||||
if len(s) != 0 && s[0] == '(' {
|
||||
if member, s, ok = consumeBareInnerList(s, nil); !ok {
|
||||
return ok
|
||||
}
|
||||
} else {
|
||||
if member, s, ok = consumeBareItem(s); !ok {
|
||||
return ok
|
||||
}
|
||||
}
|
||||
if param, s, ok = consumeParameter(s, nil); !ok {
|
||||
return ok
|
||||
}
|
||||
if f != nil {
|
||||
f(member, param)
|
||||
}
|
||||
|
||||
s = s[countLeftWhitespace(s):]
|
||||
if len(s) == 0 {
|
||||
break
|
||||
}
|
||||
if s[0] != ',' {
|
||||
return false
|
||||
}
|
||||
s = s[1:]
|
||||
s = s[countLeftWhitespace(s):]
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// consumeBareInnerList consumes an inner list
|
||||
// (https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-inner-list),
|
||||
// except for the inner list's top-most parameter.
|
||||
// For example, given `(a;b c;d);e`, it will consume only `(a;b c;d)`.
|
||||
func consumeBareInnerList(s string, f func(bareItem, param string)) (consumed, rest string, ok bool) {
|
||||
if len(s) == 0 || s[0] != '(' {
|
||||
return "", s, false
|
||||
}
|
||||
rest = s[1:]
|
||||
for len(rest) != 0 {
|
||||
var bareItem, param string
|
||||
rest = rest[countLeftWhitespace(rest):]
|
||||
if len(rest) != 0 && rest[0] == ')' {
|
||||
rest = rest[1:]
|
||||
break
|
||||
}
|
||||
if bareItem, rest, ok = consumeBareItem(rest); !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
if param, rest, ok = consumeParameter(rest, nil); !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
if len(rest) == 0 || (rest[0] != ')' && !isSP(rest[0])) {
|
||||
return "", s, false
|
||||
}
|
||||
if f != nil {
|
||||
f(bareItem, param)
|
||||
}
|
||||
}
|
||||
return s[:len(s)-len(rest)], rest, true
|
||||
}
|
||||
|
||||
// ParseBareInnerList parses a bare inner list from a given HTTP Structured
|
||||
// Field Values.
|
||||
//
|
||||
// We define a bare inner list as an inner list
|
||||
// (https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-inner-list),
|
||||
// without the top-most parameter of the inner list. For example, given the
|
||||
// inner list `(a;b c;d);e`, the bare inner list would be `(a;b c;d)`.
|
||||
//
|
||||
// Given an HTTP SFV string that represents a bare inner list, it will call the
|
||||
// given function using each of the bare item and parameter within the bare
|
||||
// inner list. This allows the caller to extract information out of the bare
|
||||
// inner list.
|
||||
//
|
||||
// This function will return once it encounters the end of the bare inner list,
|
||||
// or something that is not a bare inner list. If it cannot consume the entire
|
||||
// given string, the ok value returned will be false.
|
||||
func ParseBareInnerList(s string, f func(bareItem, param string)) (ok bool) {
|
||||
_, rest, ok := consumeBareInnerList(s, f)
|
||||
return rest == "" && ok
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-item.
|
||||
func consumeItem(s string, f func(bareItem, param string)) (consumed, rest string, ok bool) {
|
||||
var bareItem, param string
|
||||
if bareItem, rest, ok = consumeBareItem(s); !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
if param, rest, ok = consumeParameter(rest, nil); !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
if f != nil {
|
||||
f(bareItem, param)
|
||||
}
|
||||
return s[:len(s)-len(rest)], rest, true
|
||||
}
|
||||
|
||||
// ParseItem parses an item from a given HTTP Structured Field Values.
|
||||
//
|
||||
// Given an HTTP SFV string that represents an item, it will call the given
|
||||
// function once, with the bare item and the parameter of the item. This allows
|
||||
// the caller to extract information out of the item.
|
||||
//
|
||||
// This function will return once it encounters the end of the string, or
|
||||
// something that is not an item. If it cannot consume the entire given
|
||||
// string, the ok value returned will be false.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-item.
|
||||
func ParseItem(s string, f func(bareItem, param string)) (ok bool) {
|
||||
_, rest, ok := consumeItem(s, f)
|
||||
return rest == "" && ok
|
||||
}
|
||||
|
||||
// ParseDictionary parses a dictionary from a given HTTP Structured Field
|
||||
// Values.
|
||||
//
|
||||
// Given an HTTP SFV string that represents a dictionary, it will call the
|
||||
// given function using each of the keys, values, and parameters contained in
|
||||
// the dictionary. This allows the caller to extract information out of the
|
||||
// dictionary.
|
||||
//
|
||||
// This function will return once it encounters the end of the string, or
|
||||
// something that is not a dictionary. If it cannot consume the entire given
|
||||
// string, the ok value returned will be false.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-dictionary.
|
||||
func ParseDictionary(s string, f func(key, val, param string)) (ok bool) {
|
||||
for len(s) != 0 {
|
||||
var key, val, param string
|
||||
val = "?1" // Default value for empty val is boolean true.
|
||||
if key, s, ok = consumeKey(s); !ok {
|
||||
return ok
|
||||
}
|
||||
if len(s) != 0 && s[0] == '=' {
|
||||
s = s[1:]
|
||||
if len(s) != 0 && s[0] == '(' {
|
||||
if val, s, ok = consumeBareInnerList(s, nil); !ok {
|
||||
return ok
|
||||
}
|
||||
} else {
|
||||
if val, s, ok = consumeBareItem(s); !ok {
|
||||
return ok
|
||||
}
|
||||
}
|
||||
}
|
||||
if param, s, ok = consumeParameter(s, nil); !ok {
|
||||
return ok
|
||||
}
|
||||
if f != nil {
|
||||
f(key, val, param)
|
||||
}
|
||||
s = s[countLeftWhitespace(s):]
|
||||
if len(s) == 0 {
|
||||
break
|
||||
}
|
||||
if s[0] == ',' {
|
||||
s = s[1:]
|
||||
}
|
||||
s = s[countLeftWhitespace(s):]
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#parse-param.
|
||||
func consumeParameter(s string, f func(key, val string)) (consumed, rest string, ok bool) {
|
||||
rest = s
|
||||
for len(rest) != 0 {
|
||||
var key, val string
|
||||
val = "?1" // Default value for empty val is boolean true.
|
||||
if rest[0] != ';' {
|
||||
break
|
||||
}
|
||||
rest = rest[1:]
|
||||
rest = rest[countLeftWhitespace(rest):]
|
||||
key, rest, ok = consumeKey(rest)
|
||||
if !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
if len(rest) != 0 && rest[0] == '=' {
|
||||
rest = rest[1:]
|
||||
val, rest, ok = consumeBareItem(rest)
|
||||
if !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
}
|
||||
if f != nil {
|
||||
f(key, val)
|
||||
}
|
||||
}
|
||||
return s[:len(s)-len(rest)], rest, true
|
||||
}
|
||||
|
||||
// ParseParameter parses a parameter from a given HTTP Structured Field Values.
|
||||
//
|
||||
// Given an HTTP SFV string that represents a parameter, it will call the given
|
||||
// function using each of the keys and values contained in the parameter. This
|
||||
// allows the caller to extract information out of the parameter.
|
||||
//
|
||||
// This function will return once it encounters the end of the string, or
|
||||
// something that is not a parameter. If it cannot consume the entire given
|
||||
// string, the ok value returned will be false.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#parse-param.
|
||||
func ParseParameter(s string, f func(key, val string)) (ok bool) {
|
||||
_, rest, ok := consumeParameter(s, f)
|
||||
return rest == "" && ok
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-key.
|
||||
func consumeKey(s string) (consumed, rest string, ok bool) {
|
||||
if len(s) == 0 || (!isLCAlpha(s[0]) && s[0] != '*') {
|
||||
return "", s, false
|
||||
}
|
||||
i := 0
|
||||
for _, ch := range []byte(s) {
|
||||
if !isLCAlpha(ch) && !isDigit(ch) && !slices.Contains([]byte("_-.*"), ch) {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
return s[:i], s[i:], true
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-integer-or-decim.
|
||||
func consumeIntegerOrDecimal(s string) (consumed, rest string, ok bool) {
|
||||
var i, signOffset, periodIndex int
|
||||
var isDecimal bool
|
||||
if i < len(s) && s[i] == '-' {
|
||||
i++
|
||||
signOffset++
|
||||
}
|
||||
if i >= len(s) {
|
||||
return "", s, false
|
||||
}
|
||||
if !isDigit(s[i]) {
|
||||
return "", s, false
|
||||
}
|
||||
for i < len(s) {
|
||||
ch := s[i]
|
||||
if isDigit(ch) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if !isDecimal && ch == '.' {
|
||||
if i-signOffset > 12 {
|
||||
return "", s, false
|
||||
}
|
||||
periodIndex = i
|
||||
isDecimal = true
|
||||
i++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
if !isDecimal && i-signOffset > 15 {
|
||||
return "", s, false
|
||||
}
|
||||
if isDecimal {
|
||||
if i-signOffset > 16 {
|
||||
return "", s, false
|
||||
}
|
||||
if s[i-1] == '.' {
|
||||
return "", s, false
|
||||
}
|
||||
if i-periodIndex-1 > 3 {
|
||||
return "", s, false
|
||||
}
|
||||
}
|
||||
return s[:i], s[i:], true
|
||||
}
|
||||
|
||||
// ParseInteger parses an integer from a given HTTP Structured Field Values.
|
||||
//
|
||||
// The entire HTTP SFV string must consist of a valid integer. It returns the
|
||||
// parsed integer and an ok boolean value, indicating success or not.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-integer-or-decim.
|
||||
func ParseInteger(s string) (parsed int64, ok bool) {
|
||||
if _, rest, ok := consumeIntegerOrDecimal(s); !ok || rest != "" {
|
||||
return 0, false
|
||||
}
|
||||
if n, err := strconv.ParseInt(s, 10, 64); err == nil {
|
||||
return n, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// ParseDecimal parses a decimal from a given HTTP Structured Field Values.
|
||||
//
|
||||
// The entire HTTP SFV string must consist of a valid decimal. It returns the
|
||||
// parsed decimal and an ok boolean value, indicating success or not.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-integer-or-decim.
|
||||
func ParseDecimal(s string) (parsed float64, ok bool) {
|
||||
if _, rest, ok := consumeIntegerOrDecimal(s); !ok || rest != "" {
|
||||
return 0, false
|
||||
}
|
||||
if !strings.Contains(s, ".") {
|
||||
return 0, false
|
||||
}
|
||||
if n, err := strconv.ParseFloat(s, 64); err == nil {
|
||||
return n, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-string.
|
||||
func consumeString(s string) (consumed, rest string, ok bool) {
|
||||
if len(s) == 0 || s[0] != '"' {
|
||||
return "", s, false
|
||||
}
|
||||
for i := 1; i < len(s); i++ {
|
||||
switch ch := s[i]; ch {
|
||||
case '\\':
|
||||
if i+1 >= len(s) {
|
||||
return "", s, false
|
||||
}
|
||||
i++
|
||||
if ch = s[i]; ch != '"' && ch != '\\' {
|
||||
return "", s, false
|
||||
}
|
||||
case '"':
|
||||
return s[:i+1], s[i+1:], true
|
||||
default:
|
||||
if !isVChar(ch) && !isSP(ch) {
|
||||
return "", s, false
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", s, false
|
||||
}
|
||||
|
||||
// ParseString parses a Go string from a given HTTP Structured Field Values.
|
||||
//
|
||||
// The entire HTTP SFV string must consist of a valid string. It returns the
|
||||
// parsed string and an ok boolean value, indicating success or not.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-string.
|
||||
func ParseString(s string) (parsed string, ok bool) {
|
||||
if _, rest, ok := consumeString(s); !ok || rest != "" {
|
||||
return "", false
|
||||
}
|
||||
return s[1 : len(s)-1], true
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-token
|
||||
func consumeToken(s string) (consumed, rest string, ok bool) {
|
||||
if len(s) == 0 || (!isAlpha(s[0]) && s[0] != '*') {
|
||||
return "", s, false
|
||||
}
|
||||
i := 0
|
||||
for _, ch := range []byte(s) {
|
||||
if !isTChar(ch) && !slices.Contains([]byte(":/"), ch) {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
return s[:i], s[i:], true
|
||||
}
|
||||
|
||||
// ParseToken parses a token from a given HTTP Structured Field Values.
|
||||
//
|
||||
// The entire HTTP SFV string must consist of a valid token. It returns the
|
||||
// parsed token and an ok boolean value, indicating success or not.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-token
|
||||
func ParseToken(s string) (parsed string, ok bool) {
|
||||
if _, rest, ok := consumeToken(s); !ok || rest != "" {
|
||||
return "", false
|
||||
}
|
||||
return s, true
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-byte-sequence.
|
||||
func consumeByteSequence(s string) (consumed, rest string, ok bool) {
|
||||
if len(s) == 0 || s[0] != ':' {
|
||||
return "", s, false
|
||||
}
|
||||
for i := 1; i < len(s); i++ {
|
||||
if ch := s[i]; ch == ':' {
|
||||
return s[:i+1], s[i+1:], true
|
||||
}
|
||||
if ch := s[i]; !isAlpha(ch) && !isDigit(ch) && !slices.Contains([]byte("+/="), ch) {
|
||||
return "", s, false
|
||||
}
|
||||
}
|
||||
return "", s, false
|
||||
}
|
||||
|
||||
// ParseByteSequence parses a byte sequence from a given HTTP Structured Field
|
||||
// Values.
|
||||
//
|
||||
// The entire HTTP SFV string must consist of a valid byte sequence. It returns
|
||||
// the parsed byte sequence and an ok boolean value, indicating success or not.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-byte-sequence.
|
||||
func ParseByteSequence(s string) (parsed []byte, ok bool) {
|
||||
if _, rest, ok := consumeByteSequence(s); !ok || rest != "" {
|
||||
return nil, false
|
||||
}
|
||||
return []byte(s[1 : len(s)-1]), true
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-boolean.
|
||||
func consumeBoolean(s string) (consumed, rest string, ok bool) {
|
||||
if len(s) >= 2 && (s[:2] == "?0" || s[:2] == "?1") {
|
||||
return s[:2], s[2:], true
|
||||
}
|
||||
return "", s, false
|
||||
}
|
||||
|
||||
// ParseBoolean parses a boolean from a given HTTP Structured Field Values.
|
||||
//
|
||||
// The entire HTTP SFV string must consist of a valid boolean. It returns the
|
||||
// parsed boolean and an ok boolean value, indicating success or not.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-boolean.
|
||||
func ParseBoolean(s string) (parsed bool, ok bool) {
|
||||
if _, rest, ok := consumeBoolean(s); !ok || rest != "" {
|
||||
return false, false
|
||||
}
|
||||
return s == "?1", true
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-date.
|
||||
func consumeDate(s string) (consumed, rest string, ok bool) {
|
||||
if len(s) == 0 || s[0] != '@' {
|
||||
return "", s, false
|
||||
}
|
||||
if _, rest, ok = consumeIntegerOrDecimal(s[1:]); !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
consumed = s[:len(s)-len(rest)]
|
||||
if slices.Contains([]byte(consumed), '.') {
|
||||
return "", s, false
|
||||
}
|
||||
return consumed, rest, ok
|
||||
}
|
||||
|
||||
// ParseDate parses a date from a given HTTP Structured Field Values.
|
||||
//
|
||||
// The entire HTTP SFV string must consist of a valid date. It returns the
|
||||
// parsed date and an ok boolean value, indicating success or not.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-date.
|
||||
func ParseDate(s string) (parsed time.Time, ok bool) {
|
||||
if _, rest, ok := consumeDate(s); !ok || rest != "" {
|
||||
return time.Time{}, false
|
||||
}
|
||||
if n, ok := ParseInteger(s[1:]); !ok {
|
||||
return time.Time{}, false
|
||||
} else {
|
||||
return time.Unix(n, 0), true
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-display-string.
|
||||
func consumeDisplayString(s string) (consumed, rest string, ok bool) {
|
||||
// To prevent excessive allocation, especially when input is large, we
|
||||
// maintain a buffer of 4 bytes to keep track of the last rune we
|
||||
// encounter. This way, we can validate that the display string conforms to
|
||||
// UTF-8 without actually building the whole string.
|
||||
var lastRune [4]byte
|
||||
var runeLen int
|
||||
isPartOfValidRune := func(ch byte) bool {
|
||||
lastRune[runeLen] = ch
|
||||
runeLen++
|
||||
if utf8.FullRune(lastRune[:runeLen]) {
|
||||
r, s := utf8.DecodeRune(lastRune[:runeLen])
|
||||
if r == utf8.RuneError {
|
||||
return false
|
||||
}
|
||||
copy(lastRune[:], lastRune[s:runeLen])
|
||||
runeLen -= s
|
||||
return true
|
||||
}
|
||||
return runeLen <= 4
|
||||
}
|
||||
|
||||
if len(s) <= 1 || s[:2] != `%"` {
|
||||
return "", s, false
|
||||
}
|
||||
i := 2
|
||||
for i < len(s) {
|
||||
ch := s[i]
|
||||
if !isVChar(ch) && !isSP(ch) {
|
||||
return "", s, false
|
||||
}
|
||||
switch ch {
|
||||
case '"':
|
||||
if runeLen > 0 {
|
||||
return "", s, false
|
||||
}
|
||||
return s[:i+1], s[i+1:], true
|
||||
case '%':
|
||||
if i+2 >= len(s) {
|
||||
return "", s, false
|
||||
}
|
||||
if ch, ok = decOctetHex(s[i+1], s[i+2]); !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
if ok = isPartOfValidRune(ch); !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
i += 3
|
||||
default:
|
||||
if ok = isPartOfValidRune(ch); !ok {
|
||||
return "", s, ok
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
return "", s, false
|
||||
}
|
||||
|
||||
// ParseDisplayString parses a display string from a given HTTP Structured
|
||||
// Field Values.
|
||||
//
|
||||
// The entire HTTP SFV string must consist of a valid display string. It
|
||||
// returns the parsed display string and an ok boolean value, indicating
|
||||
// success or not.
|
||||
//
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-display-string.
|
||||
func ParseDisplayString(s string) (parsed string, ok bool) {
|
||||
if _, rest, ok := consumeDisplayString(s); !ok || rest != "" {
|
||||
return "", false
|
||||
}
|
||||
// consumeDisplayString() already validates that we have a valid display
|
||||
// string. Therefore, we can just construct the display string, without
|
||||
// validating it again.
|
||||
s = s[2 : len(s)-1]
|
||||
var b strings.Builder
|
||||
for i := 0; i < len(s); {
|
||||
if s[i] == '%' {
|
||||
decoded, _ := decOctetHex(s[i+1], s[i+2])
|
||||
b.WriteByte(decoded)
|
||||
i += 3
|
||||
continue
|
||||
}
|
||||
b.WriteByte(s[i])
|
||||
i++
|
||||
}
|
||||
return b.String(), true
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc9651.html#parse-bare-item.
|
||||
func consumeBareItem(s string) (consumed, rest string, ok bool) {
|
||||
if len(s) == 0 {
|
||||
return "", s, false
|
||||
}
|
||||
ch := s[0]
|
||||
switch {
|
||||
case ch == '-' || isDigit(ch):
|
||||
return consumeIntegerOrDecimal(s)
|
||||
case ch == '"':
|
||||
return consumeString(s)
|
||||
case ch == '*' || isAlpha(ch):
|
||||
return consumeToken(s)
|
||||
case ch == ':':
|
||||
return consumeByteSequence(s)
|
||||
case ch == '?':
|
||||
return consumeBoolean(s)
|
||||
case ch == '@':
|
||||
return consumeDate(s)
|
||||
case ch == '%':
|
||||
return consumeDisplayString(s)
|
||||
default:
|
||||
return "", s, false
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,6 +2,6 @@
|
||||
// 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
|
||||
//go:build darwin
|
||||
|
||||
// This exists solely so we can linkname in symbols from syscall.
|
||||
|
||||
+5
-2
@@ -6,7 +6,10 @@
|
||||
|
||||
package socket
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
|
||||
for i := range vs {
|
||||
@@ -31,5 +34,5 @@ func (h *msghdr) controllen() int {
|
||||
}
|
||||
|
||||
func (h *msghdr) flags() int {
|
||||
return int(NativeEndian.Uint32(h.Pad_cgo_2[:]))
|
||||
return int(binary.NativeEndian.Uint32(h.Pad_cgo_2[:]))
|
||||
}
|
||||
|
||||
+3
-2
@@ -7,6 +7,7 @@
|
||||
package socket // import "golang.org/x/net/internal/socket"
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"runtime"
|
||||
@@ -58,7 +59,7 @@ func (o *Option) GetInt(c *Conn) (int, error) {
|
||||
if o.Len == 1 {
|
||||
return int(b[0]), nil
|
||||
}
|
||||
return int(NativeEndian.Uint32(b[:4])), nil
|
||||
return int(binary.NativeEndian.Uint32(b[:4])), nil
|
||||
}
|
||||
|
||||
// Set writes the option and value to the kernel.
|
||||
@@ -84,7 +85,7 @@ func (o *Option) SetInt(c *Conn, v int) error {
|
||||
b = []byte{byte(v)}
|
||||
} else {
|
||||
var bb [4]byte
|
||||
NativeEndian.PutUint32(bb[:o.Len], uint32(v))
|
||||
binary.NativeEndian.PutUint32(bb[:o.Len], uint32(v))
|
||||
b = bb[:4]
|
||||
}
|
||||
return o.set(c, b)
|
||||
|
||||
-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.
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// NativeEndian is the machine native endian implementation of ByteOrder.
|
||||
var NativeEndian binary.ByteOrder
|
||||
|
||||
func init() {
|
||||
i := uint32(1)
|
||||
b := (*[4]byte)(unsafe.Pointer(&i))
|
||||
if b[0] == 1 {
|
||||
NativeEndian = binary.LittleEndian
|
||||
} else {
|
||||
NativeEndian = binary.BigEndian
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -36,7 +36,7 @@ func marshalSockaddr(ip net.IP, port int, zone string, b []byte) int {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
switch runtime.GOOS {
|
||||
case "android", "illumos", "linux", "solaris", "windows":
|
||||
NativeEndian.PutUint16(b[:2], uint16(sysAF_INET))
|
||||
binary.NativeEndian.PutUint16(b[:2], uint16(sysAF_INET))
|
||||
default:
|
||||
b[0] = sizeofSockaddrInet4
|
||||
b[1] = sysAF_INET
|
||||
@@ -48,7 +48,7 @@ func marshalSockaddr(ip net.IP, port int, zone string, b []byte) int {
|
||||
if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
|
||||
switch runtime.GOOS {
|
||||
case "android", "illumos", "linux", "solaris", "windows":
|
||||
NativeEndian.PutUint16(b[:2], uint16(sysAF_INET6))
|
||||
binary.NativeEndian.PutUint16(b[:2], uint16(sysAF_INET6))
|
||||
default:
|
||||
b[0] = sizeofSockaddrInet6
|
||||
b[1] = sysAF_INET6
|
||||
@@ -56,7 +56,7 @@ func marshalSockaddr(ip net.IP, port int, zone string, b []byte) int {
|
||||
binary.BigEndian.PutUint16(b[2:4], uint16(port))
|
||||
copy(b[8:24], ip6)
|
||||
if zone != "" {
|
||||
NativeEndian.PutUint32(b[24:28], uint32(zoneCache.index(zone)))
|
||||
binary.NativeEndian.PutUint32(b[24:28], uint32(zoneCache.index(zone)))
|
||||
}
|
||||
return sizeofSockaddrInet6
|
||||
}
|
||||
@@ -70,7 +70,7 @@ func parseInetAddr(b []byte, network string) (net.Addr, error) {
|
||||
var af int
|
||||
switch runtime.GOOS {
|
||||
case "android", "illumos", "linux", "solaris", "windows":
|
||||
af = int(NativeEndian.Uint16(b[:2]))
|
||||
af = int(binary.NativeEndian.Uint16(b[:2]))
|
||||
default:
|
||||
af = int(b[1])
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func parseInetAddr(b []byte, network string) (net.Addr, error) {
|
||||
}
|
||||
ip = make(net.IP, net.IPv6len)
|
||||
copy(ip, b[8:24])
|
||||
if id := int(NativeEndian.Uint32(b[24:28])); id > 0 {
|
||||
if id := int(binary.NativeEndian.Uint32(b[24:28])); id > 0 {
|
||||
zone = zoneCache.name(id)
|
||||
}
|
||||
}
|
||||
|
||||
+8
-10
@@ -9,8 +9,6 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/net/internal/socket"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -68,12 +66,12 @@ func (h *Header) Marshal() ([]byte, error) {
|
||||
flagsAndFragOff := (h.FragOff & 0x1fff) | int(h.Flags<<13)
|
||||
switch runtime.GOOS {
|
||||
case "darwin", "ios", "dragonfly", "netbsd":
|
||||
socket.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
|
||||
socket.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
|
||||
binary.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
|
||||
binary.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
|
||||
case "freebsd":
|
||||
if freebsdVersion < 1100000 {
|
||||
socket.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
|
||||
socket.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
|
||||
binary.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
|
||||
binary.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
|
||||
} else {
|
||||
binary.BigEndian.PutUint16(b[2:4], uint16(h.TotalLen))
|
||||
binary.BigEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
|
||||
@@ -127,15 +125,15 @@ func (h *Header) Parse(b []byte) error {
|
||||
h.Dst = net.IPv4(b[16], b[17], b[18], b[19])
|
||||
switch runtime.GOOS {
|
||||
case "darwin", "ios", "dragonfly", "netbsd":
|
||||
h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4])) + hdrlen
|
||||
h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
|
||||
h.TotalLen = int(binary.NativeEndian.Uint16(b[2:4])) + hdrlen
|
||||
h.FragOff = int(binary.NativeEndian.Uint16(b[6:8]))
|
||||
case "freebsd":
|
||||
if freebsdVersion < 1100000 {
|
||||
h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4]))
|
||||
h.TotalLen = int(binary.NativeEndian.Uint16(b[2:4]))
|
||||
if freebsdVersion < 1000000 {
|
||||
h.TotalLen += hdrlen
|
||||
}
|
||||
h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
|
||||
h.FragOff = int(binary.NativeEndian.Uint16(b[6:8]))
|
||||
} else {
|
||||
h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
|
||||
h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@
|
||||
package ipv6
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/net/internal/iana"
|
||||
@@ -19,7 +20,7 @@ func marshal2292HopLimit(b []byte, cm *ControlMessage) []byte {
|
||||
m := socket.ControlMessage(b)
|
||||
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_2292HOPLIMIT, 4)
|
||||
if cm != nil {
|
||||
socket.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
|
||||
binary.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
|
||||
}
|
||||
return m.Next(4)
|
||||
}
|
||||
|
||||
+5
-4
@@ -7,6 +7,7 @@
|
||||
package ipv6
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"unsafe"
|
||||
|
||||
@@ -20,26 +21,26 @@ func marshalTrafficClass(b []byte, cm *ControlMessage) []byte {
|
||||
m := socket.ControlMessage(b)
|
||||
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_TCLASS, 4)
|
||||
if cm != nil {
|
||||
socket.NativeEndian.PutUint32(m.Data(4), uint32(cm.TrafficClass))
|
||||
binary.NativeEndian.PutUint32(m.Data(4), uint32(cm.TrafficClass))
|
||||
}
|
||||
return m.Next(4)
|
||||
}
|
||||
|
||||
func parseTrafficClass(cm *ControlMessage, b []byte) {
|
||||
cm.TrafficClass = int(socket.NativeEndian.Uint32(b[:4]))
|
||||
cm.TrafficClass = int(binary.NativeEndian.Uint32(b[:4]))
|
||||
}
|
||||
|
||||
func marshalHopLimit(b []byte, cm *ControlMessage) []byte {
|
||||
m := socket.ControlMessage(b)
|
||||
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_HOPLIMIT, 4)
|
||||
if cm != nil {
|
||||
socket.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
|
||||
binary.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
|
||||
}
|
||||
return m.Next(4)
|
||||
}
|
||||
|
||||
func parseHopLimit(cm *ControlMessage, b []byte) {
|
||||
cm.HopLimit = int(socket.NativeEndian.Uint32(b[:4]))
|
||||
cm.HopLimit = int(binary.NativeEndian.Uint32(b[:4]))
|
||||
}
|
||||
|
||||
func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
-1
File diff suppressed because one or more lines are too long
+5
@@ -51,6 +51,7 @@ package publicsuffix // import "golang.org/x/net/publicsuffix"
|
||||
import (
|
||||
"fmt"
|
||||
"net/http/cookiejar"
|
||||
"net/netip"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -84,6 +85,10 @@ func (list) String() string {
|
||||
// domains like "foo.appspot.com" can be found at
|
||||
// https://wiki.mozilla.org/Public_Suffix_List/Use_Cases
|
||||
func PublicSuffix(domain string) (publicSuffix string, icann bool) {
|
||||
if _, err := netip.ParseAddr(domain); err == nil {
|
||||
return domain, false
|
||||
}
|
||||
|
||||
lo, hi := uint32(0), uint32(numTLD)
|
||||
s, suffix, icannNode, wildcard := domain, len(domain), false, false
|
||||
loop:
|
||||
|
||||
+6
-6
@@ -4,7 +4,7 @@ package publicsuffix
|
||||
|
||||
import _ "embed"
|
||||
|
||||
const version = "publicsuffix.org's public_suffix_list.dat, git revision 2c960dac3d39ba521eb5db9da192968f5be0aded (2025-03-18T07:22:13Z)"
|
||||
const version = "publicsuffix.org's public_suffix_list.dat, git revision d6c92f1bbb7433e5db7b8405c25d4035fb8ff376 (2026-02-06T07:36:33Z)"
|
||||
|
||||
const (
|
||||
nodesBits = 40
|
||||
@@ -26,7 +26,7 @@ const (
|
||||
)
|
||||
|
||||
// numTLD is the number of top level domains.
|
||||
const numTLD = 1454
|
||||
const numTLD = 1450
|
||||
|
||||
// text is the combined text of all labels.
|
||||
//
|
||||
@@ -63,8 +63,8 @@ var nodes uint40String
|
||||
//go:embed data/children
|
||||
var children uint32String
|
||||
|
||||
// max children 870 (capacity 1023)
|
||||
// max text offset 31785 (capacity 65535)
|
||||
// max children 935 (capacity 1023)
|
||||
// max text offset 32332 (capacity 65535)
|
||||
// max text length 31 (capacity 63)
|
||||
// max hi 10100 (capacity 16383)
|
||||
// max lo 10095 (capacity 16383)
|
||||
// max hi 10533 (capacity 16383)
|
||||
// max lo 10528 (capacity 16383)
|
||||
|
||||
+2
-2
@@ -144,8 +144,8 @@ func (g *Group) SetLimit(n int) {
|
||||
g.sem = nil
|
||||
return
|
||||
}
|
||||
if len(g.sem) != 0 {
|
||||
panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", len(g.sem)))
|
||||
if active := len(g.sem); active != 0 {
|
||||
panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", active))
|
||||
}
|
||||
g.sem = make(chan token, n)
|
||||
}
|
||||
|
||||
+7
-7
@@ -22,7 +22,7 @@ var errGoexit = errors.New("runtime.Goexit was called")
|
||||
// A panicError is an arbitrary value recovered from a panic
|
||||
// with the stack trace during the execution of given function.
|
||||
type panicError struct {
|
||||
value interface{}
|
||||
value any
|
||||
stack []byte
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func (p *panicError) Unwrap() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func newPanicError(v interface{}) error {
|
||||
func newPanicError(v any) error {
|
||||
stack := debug.Stack()
|
||||
|
||||
// The first line of the stack trace is of the form "goroutine N [status]:"
|
||||
@@ -58,7 +58,7 @@ type call struct {
|
||||
|
||||
// These fields are written once before the WaitGroup is done
|
||||
// and are only read after the WaitGroup is done.
|
||||
val interface{}
|
||||
val any
|
||||
err error
|
||||
|
||||
// These fields are read and written with the singleflight
|
||||
@@ -78,7 +78,7 @@ type Group struct {
|
||||
// Result holds the results of Do, so they can be passed
|
||||
// on a channel.
|
||||
type Result struct {
|
||||
Val interface{}
|
||||
Val any
|
||||
Err error
|
||||
Shared bool
|
||||
}
|
||||
@@ -88,7 +88,7 @@ type Result struct {
|
||||
// time. If a duplicate comes in, the duplicate caller waits for the
|
||||
// original to complete and receives the same results.
|
||||
// The return value shared indicates whether v was given to multiple callers.
|
||||
func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
|
||||
func (g *Group) Do(key string, fn func() (any, error)) (v any, err error, shared bool) {
|
||||
g.mu.Lock()
|
||||
if g.m == nil {
|
||||
g.m = make(map[string]*call)
|
||||
@@ -118,7 +118,7 @@ func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, e
|
||||
// results when they are ready.
|
||||
//
|
||||
// The returned channel will not be closed.
|
||||
func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {
|
||||
func (g *Group) DoChan(key string, fn func() (any, error)) <-chan Result {
|
||||
ch := make(chan Result, 1)
|
||||
g.mu.Lock()
|
||||
if g.m == nil {
|
||||
@@ -141,7 +141,7 @@ func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result
|
||||
}
|
||||
|
||||
// doCall handles the single call for a key.
|
||||
func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
|
||||
func (g *Group) doCall(c *call, key string, fn func() (any, error)) {
|
||||
normalReturn := false
|
||||
recovered := false
|
||||
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
//go:build darwin && arm64 && gc
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT libc_sysctlbyname_trampoline<>(SB),NOSPLIT,$0-0
|
||||
JMP libc_sysctlbyname(SB)
|
||||
GLOBL ·libc_sysctlbyname_trampoline_addr(SB), RODATA, $8
|
||||
DATA ·libc_sysctlbyname_trampoline_addr(SB)/8, $libc_sysctlbyname_trampoline<>(SB)
|
||||
+3
-6
@@ -44,14 +44,11 @@ func initOptions() {
|
||||
}
|
||||
|
||||
func archInit() {
|
||||
switch runtime.GOOS {
|
||||
case "freebsd":
|
||||
if runtime.GOOS == "freebsd" {
|
||||
readARM64Registers()
|
||||
case "linux", "netbsd", "openbsd":
|
||||
} else {
|
||||
// Most platforms don't seem to allow directly reading these registers.
|
||||
doinit()
|
||||
default:
|
||||
// Many platforms don't seem to allow reading these registers.
|
||||
setMinimalFeatures()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-8
@@ -9,31 +9,27 @@
|
||||
// func getisar0() uint64
|
||||
TEXT ·getisar0(SB),NOSPLIT,$0-8
|
||||
// get Instruction Set Attributes 0 into x0
|
||||
// mrs x0, ID_AA64ISAR0_EL1 = d5380600
|
||||
WORD $0xd5380600
|
||||
MRS ID_AA64ISAR0_EL1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func getisar1() uint64
|
||||
TEXT ·getisar1(SB),NOSPLIT,$0-8
|
||||
// get Instruction Set Attributes 1 into x0
|
||||
// mrs x0, ID_AA64ISAR1_EL1 = d5380620
|
||||
WORD $0xd5380620
|
||||
MRS ID_AA64ISAR1_EL1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func getpfr0() uint64
|
||||
TEXT ·getpfr0(SB),NOSPLIT,$0-8
|
||||
// get Processor Feature Register 0 into x0
|
||||
// mrs x0, ID_AA64PFR0_EL1 = d5380400
|
||||
WORD $0xd5380400
|
||||
MRS ID_AA64PFR0_EL1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func getzfr0() uint64
|
||||
TEXT ·getzfr0(SB),NOSPLIT,$0-8
|
||||
// get SVE Feature Register 0 into x0
|
||||
// mrs x0, ID_AA64ZFR0_EL1 = d5380480
|
||||
WORD $0xd5380480
|
||||
MRS ID_AA64ZFR0_EL1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
RET
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
// Copyright 2026 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.
|
||||
|
||||
//go:build darwin && arm64 && gc
|
||||
|
||||
package cpu
|
||||
|
||||
func doinit() {
|
||||
setMinimalFeatures()
|
||||
|
||||
// The feature flags are explained in [Instruction Set Detection].
|
||||
// There are some differences between MacOS versions:
|
||||
//
|
||||
// MacOS 11 and 12 do not have "hw.optional" sysctl values for some of the features.
|
||||
//
|
||||
// MacOS 13 changed some of the naming conventions to align with ARM Architecture Reference Manual.
|
||||
// For example "hw.optional.armv8_2_sha512" became "hw.optional.arm.FEAT_SHA512".
|
||||
// It currently checks both to stay compatible with MacOS 11 and 12.
|
||||
// The old names also work with MacOS 13, however it's not clear whether
|
||||
// they will continue working with future OS releases.
|
||||
//
|
||||
// Once MacOS 12 is no longer supported the old names can be removed.
|
||||
//
|
||||
// [Instruction Set Detection]: https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
|
||||
|
||||
// Encryption, hashing and checksum capabilities
|
||||
|
||||
// For the following flags there are no MacOS 11 sysctl flags.
|
||||
ARM64.HasAES = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_AES\x00"))
|
||||
ARM64.HasPMULL = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_PMULL\x00"))
|
||||
ARM64.HasSHA1 = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA1\x00"))
|
||||
ARM64.HasSHA2 = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA256\x00"))
|
||||
|
||||
ARM64.HasSHA3 = darwinSysctlEnabled([]byte("hw.optional.armv8_2_sha3\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA3\x00"))
|
||||
ARM64.HasSHA512 = darwinSysctlEnabled([]byte("hw.optional.armv8_2_sha512\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA512\x00"))
|
||||
|
||||
ARM64.HasCRC32 = darwinSysctlEnabled([]byte("hw.optional.armv8_crc32\x00"))
|
||||
|
||||
// Atomic and memory ordering
|
||||
ARM64.HasATOMICS = darwinSysctlEnabled([]byte("hw.optional.armv8_1_atomics\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_LSE\x00"))
|
||||
ARM64.HasLRCPC = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_LRCPC\x00"))
|
||||
|
||||
// SIMD and floating point capabilities
|
||||
ARM64.HasFPHP = darwinSysctlEnabled([]byte("hw.optional.neon_fp16\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_FP16\x00"))
|
||||
ARM64.HasASIMDHP = darwinSysctlEnabled([]byte("hw.optional.neon_hpfp\x00")) || darwinSysctlEnabled([]byte("hw.optional.AdvSIMD_HPFPCvt\x00"))
|
||||
ARM64.HasASIMDRDM = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_RDM\x00"))
|
||||
ARM64.HasASIMDDP = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_DotProd\x00"))
|
||||
ARM64.HasASIMDFHM = darwinSysctlEnabled([]byte("hw.optional.armv8_2_fhm\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_FHM\x00"))
|
||||
ARM64.HasI8MM = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_I8MM\x00"))
|
||||
|
||||
ARM64.HasJSCVT = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_JSCVT\x00"))
|
||||
ARM64.HasFCMA = darwinSysctlEnabled([]byte("hw.optional.armv8_3_compnum\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_FCMA\x00"))
|
||||
|
||||
// Miscellaneous
|
||||
ARM64.HasDCPOP = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_DPB\x00"))
|
||||
ARM64.HasEVTSTRM = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_ECV\x00"))
|
||||
ARM64.HasDIT = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_DIT\x00"))
|
||||
|
||||
// Not supported, but added for completeness
|
||||
ARM64.HasCPUID = false
|
||||
|
||||
ARM64.HasSM3 = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SM3\x00"))
|
||||
ARM64.HasSM4 = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SM4\x00"))
|
||||
ARM64.HasSVE = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SVE\x00"))
|
||||
ARM64.HasSVE2 = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SVE2\x00"))
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright 2026 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.
|
||||
|
||||
//go:build darwin && arm64 && !gc
|
||||
|
||||
package cpu
|
||||
|
||||
func doinit() {
|
||||
setMinimalFeatures()
|
||||
|
||||
ARM64.HasASIMD = true
|
||||
ARM64.HasFP = true
|
||||
|
||||
// Go already assumes these to be available because they were on the M1
|
||||
// and these are supported on all Apple arm64 chips.
|
||||
ARM64.HasAES = true
|
||||
ARM64.HasPMULL = true
|
||||
ARM64.HasSHA1 = true
|
||||
ARM64.HasSHA2 = true
|
||||
|
||||
if runtime.GOOS != "ios" {
|
||||
// Apple A7 processors do not support these, however
|
||||
// M-series SoCs are at least armv8.4-a
|
||||
ARM64.HasCRC32 = true // armv8.1
|
||||
ARM64.HasATOMICS = true // armv8.2
|
||||
ARM64.HasJSCVT = true // armv8.3, if HasFP
|
||||
}
|
||||
}
|
||||
+1
@@ -9,3 +9,4 @@ package cpu
|
||||
func getisar0() uint64 { return 0 }
|
||||
func getisar1() uint64 { return 0 }
|
||||
func getpfr0() uint64 { return 0 }
|
||||
func getzfr0() uint64 { return 0 }
|
||||
|
||||
+4
-2
@@ -2,8 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !linux && !netbsd && !openbsd && arm64
|
||||
//go:build !darwin && !linux && !netbsd && !openbsd && !windows && arm64
|
||||
|
||||
package cpu
|
||||
|
||||
func doinit() {}
|
||||
func doinit() {
|
||||
setMinimalFeatures()
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// Copyright 2026 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 cpu
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func doinit() {
|
||||
// set HasASIMD and HasFP to true as per
|
||||
// https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#base-requirements
|
||||
//
|
||||
// The ARM64 version of Windows always presupposes that it's running on an ARMv8 or later architecture.
|
||||
// Both floating-point and NEON support are presumed to be present in hardware.
|
||||
//
|
||||
ARM64.HasASIMD = true
|
||||
ARM64.HasFP = true
|
||||
|
||||
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasAES = true
|
||||
ARM64.HasPMULL = true
|
||||
ARM64.HasSHA1 = true
|
||||
ARM64.HasSHA2 = true
|
||||
}
|
||||
ARM64.HasSHA3 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasCRC32 = windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSHA512 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasATOMICS = windows.IsProcessorFeaturePresent(windows.PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
|
||||
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasASIMDDP = true
|
||||
ARM64.HasASIMDRDM = true
|
||||
}
|
||||
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasLRCPC = true
|
||||
ARM64.HasSM3 = true
|
||||
}
|
||||
ARM64.HasSVE = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSVE2 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasJSCVT = windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
|
||||
}
|
||||
+122
-48
@@ -64,6 +64,80 @@ func initOptions() {
|
||||
|
||||
func archInit() {
|
||||
|
||||
// From internal/cpu
|
||||
const (
|
||||
// eax bits
|
||||
cpuid_AVXVNNI = 1 << 4
|
||||
|
||||
// ecx bits
|
||||
cpuid_SSE3 = 1 << 0
|
||||
cpuid_PCLMULQDQ = 1 << 1
|
||||
cpuid_AVX512VBMI = 1 << 1
|
||||
cpuid_AVX512VBMI2 = 1 << 6
|
||||
cpuid_SSSE3 = 1 << 9
|
||||
cpuid_AVX512GFNI = 1 << 8
|
||||
cpuid_AVX512VAES = 1 << 9
|
||||
cpuid_AVX512VNNI = 1 << 11
|
||||
cpuid_AVX512BITALG = 1 << 12
|
||||
cpuid_FMA = 1 << 12
|
||||
cpuid_AVX512VPOPCNTDQ = 1 << 14
|
||||
cpuid_SSE41 = 1 << 19
|
||||
cpuid_SSE42 = 1 << 20
|
||||
cpuid_POPCNT = 1 << 23
|
||||
cpuid_AES = 1 << 25
|
||||
cpuid_OSXSAVE = 1 << 27
|
||||
cpuid_AVX = 1 << 28
|
||||
|
||||
// "Extended Feature Flag" bits returned in EBX for CPUID EAX=0x7 ECX=0x0
|
||||
cpuid_BMI1 = 1 << 3
|
||||
cpuid_AVX2 = 1 << 5
|
||||
cpuid_BMI2 = 1 << 8
|
||||
cpuid_ERMS = 1 << 9
|
||||
cpuid_AVX512F = 1 << 16
|
||||
cpuid_AVX512DQ = 1 << 17
|
||||
cpuid_ADX = 1 << 19
|
||||
cpuid_AVX512CD = 1 << 28
|
||||
cpuid_SHA = 1 << 29
|
||||
cpuid_AVX512BW = 1 << 30
|
||||
cpuid_AVX512VL = 1 << 31
|
||||
|
||||
// "Extended Feature Flag" bits returned in ECX for CPUID EAX=0x7 ECX=0x0
|
||||
cpuid_AVX512_VBMI = 1 << 1
|
||||
cpuid_AVX512_VBMI2 = 1 << 6
|
||||
cpuid_GFNI = 1 << 8
|
||||
cpuid_AVX512VPCLMULQDQ = 1 << 10
|
||||
cpuid_AVX512_BITALG = 1 << 12
|
||||
|
||||
// edx bits
|
||||
cpuid_FSRM = 1 << 4
|
||||
// edx bits for CPUID 0x80000001
|
||||
cpuid_RDTSCP = 1 << 27
|
||||
)
|
||||
// Additional constants not in internal/cpu
|
||||
const (
|
||||
// eax=1: edx
|
||||
cpuid_SSE2 = 1 << 26
|
||||
// eax=1: ecx
|
||||
cpuid_CX16 = 1 << 13
|
||||
cpuid_RDRAND = 1 << 30
|
||||
// eax=7,ecx=0: ebx
|
||||
cpuid_RDSEED = 1 << 18
|
||||
cpuid_AVX512IFMA = 1 << 21
|
||||
cpuid_AVX512PF = 1 << 26
|
||||
cpuid_AVX512ER = 1 << 27
|
||||
// eax=7,ecx=0: edx
|
||||
cpuid_AVX5124VNNIW = 1 << 2
|
||||
cpuid_AVX5124FMAPS = 1 << 3
|
||||
cpuid_AMXBF16 = 1 << 22
|
||||
cpuid_AMXTile = 1 << 24
|
||||
cpuid_AMXInt8 = 1 << 25
|
||||
// eax=7,ecx=1: eax
|
||||
cpuid_AVX512BF16 = 1 << 5
|
||||
cpuid_AVXIFMA = 1 << 23
|
||||
// eax=7,ecx=1: edx
|
||||
cpuid_AVXVNNIInt8 = 1 << 4
|
||||
)
|
||||
|
||||
Initialized = true
|
||||
|
||||
maxID, _, _, _ := cpuid(0, 0)
|
||||
@@ -73,90 +147,90 @@ func archInit() {
|
||||
}
|
||||
|
||||
_, _, ecx1, edx1 := cpuid(1, 0)
|
||||
X86.HasSSE2 = isSet(26, edx1)
|
||||
X86.HasSSE2 = isSet(edx1, cpuid_SSE2)
|
||||
|
||||
X86.HasSSE3 = isSet(0, ecx1)
|
||||
X86.HasPCLMULQDQ = isSet(1, ecx1)
|
||||
X86.HasSSSE3 = isSet(9, ecx1)
|
||||
X86.HasFMA = isSet(12, ecx1)
|
||||
X86.HasCX16 = isSet(13, ecx1)
|
||||
X86.HasSSE41 = isSet(19, ecx1)
|
||||
X86.HasSSE42 = isSet(20, ecx1)
|
||||
X86.HasPOPCNT = isSet(23, ecx1)
|
||||
X86.HasAES = isSet(25, ecx1)
|
||||
X86.HasOSXSAVE = isSet(27, ecx1)
|
||||
X86.HasRDRAND = isSet(30, ecx1)
|
||||
X86.HasSSE3 = isSet(ecx1, cpuid_SSE3)
|
||||
X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ)
|
||||
X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3)
|
||||
X86.HasFMA = isSet(ecx1, cpuid_FMA)
|
||||
X86.HasCX16 = isSet(ecx1, cpuid_CX16)
|
||||
X86.HasSSE41 = isSet(ecx1, cpuid_SSE41)
|
||||
X86.HasSSE42 = isSet(ecx1, cpuid_SSE42)
|
||||
X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT)
|
||||
X86.HasAES = isSet(ecx1, cpuid_AES)
|
||||
X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE)
|
||||
X86.HasRDRAND = isSet(ecx1, cpuid_RDRAND)
|
||||
|
||||
var osSupportsAVX, osSupportsAVX512 bool
|
||||
// For XGETBV, OSXSAVE bit is required and sufficient.
|
||||
if X86.HasOSXSAVE {
|
||||
eax, _ := xgetbv()
|
||||
// Check if XMM and YMM registers have OS support.
|
||||
osSupportsAVX = isSet(1, eax) && isSet(2, eax)
|
||||
osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2)
|
||||
|
||||
if runtime.GOOS == "darwin" {
|
||||
// Darwin requires special AVX512 checks, see cpu_darwin_x86.go
|
||||
osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512()
|
||||
} else {
|
||||
// Check if OPMASK and ZMM registers have OS support.
|
||||
osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax)
|
||||
osSupportsAVX512 = osSupportsAVX && isSet(eax, 1<<5) && isSet(eax, 1<<6) && isSet(eax, 1<<7)
|
||||
}
|
||||
}
|
||||
|
||||
X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
|
||||
X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX
|
||||
|
||||
if maxID < 7 {
|
||||
return
|
||||
}
|
||||
|
||||
eax7, ebx7, ecx7, edx7 := cpuid(7, 0)
|
||||
X86.HasBMI1 = isSet(3, ebx7)
|
||||
X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
|
||||
X86.HasBMI2 = isSet(8, ebx7)
|
||||
X86.HasERMS = isSet(9, ebx7)
|
||||
X86.HasRDSEED = isSet(18, ebx7)
|
||||
X86.HasADX = isSet(19, ebx7)
|
||||
X86.HasBMI1 = isSet(ebx7, cpuid_BMI1)
|
||||
X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX
|
||||
X86.HasBMI2 = isSet(ebx7, cpuid_BMI2)
|
||||
X86.HasERMS = isSet(ebx7, cpuid_ERMS)
|
||||
X86.HasRDSEED = isSet(ebx7, cpuid_RDSEED)
|
||||
X86.HasADX = isSet(ebx7, cpuid_ADX)
|
||||
|
||||
X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension
|
||||
X86.HasAVX512 = isSet(ebx7, cpuid_AVX512F) && osSupportsAVX512 // Because avx-512 foundation is the core required extension
|
||||
if X86.HasAVX512 {
|
||||
X86.HasAVX512F = true
|
||||
X86.HasAVX512CD = isSet(28, ebx7)
|
||||
X86.HasAVX512ER = isSet(27, ebx7)
|
||||
X86.HasAVX512PF = isSet(26, ebx7)
|
||||
X86.HasAVX512VL = isSet(31, ebx7)
|
||||
X86.HasAVX512BW = isSet(30, ebx7)
|
||||
X86.HasAVX512DQ = isSet(17, ebx7)
|
||||
X86.HasAVX512IFMA = isSet(21, ebx7)
|
||||
X86.HasAVX512VBMI = isSet(1, ecx7)
|
||||
X86.HasAVX5124VNNIW = isSet(2, edx7)
|
||||
X86.HasAVX5124FMAPS = isSet(3, edx7)
|
||||
X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7)
|
||||
X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7)
|
||||
X86.HasAVX512VNNI = isSet(11, ecx7)
|
||||
X86.HasAVX512GFNI = isSet(8, ecx7)
|
||||
X86.HasAVX512VAES = isSet(9, ecx7)
|
||||
X86.HasAVX512VBMI2 = isSet(6, ecx7)
|
||||
X86.HasAVX512BITALG = isSet(12, ecx7)
|
||||
X86.HasAVX512CD = isSet(ebx7, cpuid_AVX512CD)
|
||||
X86.HasAVX512ER = isSet(ebx7, cpuid_AVX512ER)
|
||||
X86.HasAVX512PF = isSet(ebx7, cpuid_AVX512PF)
|
||||
X86.HasAVX512VL = isSet(ebx7, cpuid_AVX512VL)
|
||||
X86.HasAVX512BW = isSet(ebx7, cpuid_AVX512BW)
|
||||
X86.HasAVX512DQ = isSet(ebx7, cpuid_AVX512DQ)
|
||||
X86.HasAVX512IFMA = isSet(ebx7, cpuid_AVX512IFMA)
|
||||
X86.HasAVX512VBMI = isSet(ecx7, cpuid_AVX512_VBMI)
|
||||
X86.HasAVX5124VNNIW = isSet(edx7, cpuid_AVX5124VNNIW)
|
||||
X86.HasAVX5124FMAPS = isSet(edx7, cpuid_AVX5124FMAPS)
|
||||
X86.HasAVX512VPOPCNTDQ = isSet(ecx7, cpuid_AVX512VPOPCNTDQ)
|
||||
X86.HasAVX512VPCLMULQDQ = isSet(ecx7, cpuid_AVX512VPCLMULQDQ)
|
||||
X86.HasAVX512VNNI = isSet(ecx7, cpuid_AVX512VNNI)
|
||||
X86.HasAVX512GFNI = isSet(ecx7, cpuid_AVX512GFNI)
|
||||
X86.HasAVX512VAES = isSet(ecx7, cpuid_AVX512VAES)
|
||||
X86.HasAVX512VBMI2 = isSet(ecx7, cpuid_AVX512VBMI2)
|
||||
X86.HasAVX512BITALG = isSet(ecx7, cpuid_AVX512BITALG)
|
||||
}
|
||||
|
||||
X86.HasAMXTile = isSet(24, edx7)
|
||||
X86.HasAMXInt8 = isSet(25, edx7)
|
||||
X86.HasAMXBF16 = isSet(22, edx7)
|
||||
X86.HasAMXTile = isSet(edx7, cpuid_AMXTile)
|
||||
X86.HasAMXInt8 = isSet(edx7, cpuid_AMXInt8)
|
||||
X86.HasAMXBF16 = isSet(edx7, cpuid_AMXBF16)
|
||||
|
||||
// These features depend on the second level of extended features.
|
||||
if eax7 >= 1 {
|
||||
eax71, _, _, edx71 := cpuid(7, 1)
|
||||
if X86.HasAVX512 {
|
||||
X86.HasAVX512BF16 = isSet(5, eax71)
|
||||
X86.HasAVX512BF16 = isSet(eax71, cpuid_AVX512BF16)
|
||||
}
|
||||
if X86.HasAVX {
|
||||
X86.HasAVXIFMA = isSet(23, eax71)
|
||||
X86.HasAVXVNNI = isSet(4, eax71)
|
||||
X86.HasAVXVNNIInt8 = isSet(4, edx71)
|
||||
X86.HasAVXIFMA = isSet(eax71, cpuid_AVXIFMA)
|
||||
X86.HasAVXVNNI = isSet(eax71, cpuid_AVXVNNI)
|
||||
X86.HasAVXVNNIInt8 = isSet(edx71, cpuid_AVXVNNIInt8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isSet(bitpos uint, value uint32) bool {
|
||||
return value&(1<<bitpos) != 0
|
||||
func isSet(hwc uint32, value uint32) bool {
|
||||
return hwc&value != 0
|
||||
}
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Minimal copy from internal/cpu and runtime to make sysctl calls.
|
||||
|
||||
//go:build darwin && arm64 && gc
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Errno = syscall.Errno
|
||||
|
||||
// adapted from internal/cpu/cpu_arm64_darwin.go
|
||||
func darwinSysctlEnabled(name []byte) bool {
|
||||
out := int32(0)
|
||||
nout := unsafe.Sizeof(out)
|
||||
if ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); ret != nil {
|
||||
return false
|
||||
}
|
||||
return out > 0
|
||||
}
|
||||
|
||||
//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib"
|
||||
|
||||
var libc_sysctlbyname_trampoline_addr uintptr
|
||||
|
||||
// adapted from runtime/sys_darwin.go in the pattern of sysctl() above, as defined in x/sys/unix
|
||||
func sysctlbyname(name *byte, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
|
||||
if _, _, err := syscall_syscall6(
|
||||
libc_sysctlbyname_trampoline_addr,
|
||||
uintptr(unsafe.Pointer(name)),
|
||||
uintptr(unsafe.Pointer(old)),
|
||||
uintptr(unsafe.Pointer(oldlen)),
|
||||
uintptr(unsafe.Pointer(new)),
|
||||
uintptr(newlen),
|
||||
0,
|
||||
); err != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:cgo_import_dynamic libc_sysctlbyname sysctlbyname "/usr/lib/libSystem.B.dylib"
|
||||
|
||||
// Implemented in the runtime package (runtime/sys_darwin.go)
|
||||
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
||||
|
||||
//go:linkname syscall_syscall6 syscall.syscall6
|
||||
+8
-3
@@ -6,9 +6,7 @@
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
import "unsafe"
|
||||
|
||||
// ioctl itself should not be exposed directly, but additional get/set
|
||||
// functions for specific types are permissible.
|
||||
@@ -28,6 +26,13 @@ func IoctlSetPointerInt(fd int, req int, value int) error {
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&v))
|
||||
}
|
||||
|
||||
// IoctlSetString performs an ioctl operation which sets a string value
|
||||
// on fd, using the specified request number.
|
||||
func IoctlSetString(fd int, req int, value string) error {
|
||||
bs := append([]byte(value), 0)
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
|
||||
}
|
||||
|
||||
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
//
|
||||
// To change fd's window size, the req argument should be TIOCSWINSZ.
|
||||
|
||||
+8
-3
@@ -6,9 +6,7 @@
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
import "unsafe"
|
||||
|
||||
// ioctl itself should not be exposed directly, but additional get/set
|
||||
// functions for specific types are permissible.
|
||||
@@ -28,6 +26,13 @@ func IoctlSetPointerInt(fd int, req uint, value int) error {
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&v))
|
||||
}
|
||||
|
||||
// IoctlSetString performs an ioctl operation which sets a string value
|
||||
// on fd, using the specified request number.
|
||||
func IoctlSetString(fd int, req uint, value string) error {
|
||||
bs := append([]byte(value), 0)
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
|
||||
}
|
||||
|
||||
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
//
|
||||
// To change fd's window size, the req argument should be TIOCSWINSZ.
|
||||
|
||||
+4
-1
@@ -226,6 +226,7 @@ struct ltchars {
|
||||
#include <linux/cryptouser.h>
|
||||
#include <linux/devlink.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/ethtool_netlink.h>
|
||||
#include <linux/falloc.h>
|
||||
@@ -255,6 +256,7 @@ struct ltchars {
|
||||
#include <linux/loop.h>
|
||||
#include <linux/lwtunnel.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/mei.h>
|
||||
#include <linux/memfd.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mount.h>
|
||||
@@ -529,6 +531,7 @@ ccflags="$@"
|
||||
$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ ||
|
||||
$2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ ||
|
||||
$2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ ||
|
||||
$2 ~ /^(DT|EI|ELF|EV|NN|NT|PF|SHF|SHN|SHT|STB|STT|VER)_/ ||
|
||||
$2 ~ /^O?XTABS$/ ||
|
||||
$2 ~ /^TC[IO](ON|OFF)$/ ||
|
||||
$2 ~ /^IN_/ ||
|
||||
@@ -611,7 +614,7 @@ ccflags="$@"
|
||||
$2 !~ /IOC_MAGIC/ &&
|
||||
$2 ~ /^[A-Z][A-Z0-9_]+_MAGIC2?$/ ||
|
||||
$2 ~ /^(VM|VMADDR)_/ ||
|
||||
$2 ~ /^IOCTL_VM_SOCKETS_/ ||
|
||||
$2 ~ /^(IOCTL_VM_SOCKETS_|IOCTL_MEI_)/ ||
|
||||
$2 ~ /^(TASKSTATS|TS)_/ ||
|
||||
$2 ~ /^CGROUPSTATS_/ ||
|
||||
$2 ~ /^GENL_/ ||
|
||||
|
||||
+6
@@ -2643,3 +2643,9 @@ func SchedGetAttr(pid int, flags uint) (*SchedAttr, error) {
|
||||
|
||||
//sys Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint) (err error)
|
||||
//sys Mseal(b []byte, flags uint) (err error)
|
||||
|
||||
//sys setMemPolicy(mode int, mask *CPUSet, size int) (err error) = SYS_SET_MEMPOLICY
|
||||
|
||||
func SetMemPolicy(mode int, mask *CPUSet) error {
|
||||
return setMemPolicy(mode, mask, _CPU_SETSIZE)
|
||||
}
|
||||
|
||||
-8
@@ -1052,14 +1052,6 @@ func IoctlSetIntRetInt(fd int, req int, arg int) (int, error) {
|
||||
return ioctlRet(fd, req, uintptr(arg))
|
||||
}
|
||||
|
||||
func IoctlSetString(fd int, req int, val string) error {
|
||||
bs := make([]byte, len(val)+1)
|
||||
copy(bs[:len(bs)-1], val)
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
|
||||
runtime.KeepAlive(&bs[0])
|
||||
return err
|
||||
}
|
||||
|
||||
// Lifreq Helpers
|
||||
|
||||
func (l *Lifreq) SetName(name string) error {
|
||||
|
||||
+7
-3
@@ -367,7 +367,9 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
|
||||
iov[0].SetLen(len(p))
|
||||
}
|
||||
var rsa RawSockaddrAny
|
||||
n, oobn, recvflags, err = recvmsgRaw(fd, iov[:], oob, flags, &rsa)
|
||||
if n, oobn, recvflags, err = recvmsgRaw(fd, iov[:], oob, flags, &rsa); err != nil {
|
||||
return
|
||||
}
|
||||
// source address is only specified if the socket is unconnected
|
||||
if rsa.Addr.Family != AF_UNSPEC {
|
||||
from, err = anyToSockaddr(fd, &rsa)
|
||||
@@ -389,8 +391,10 @@ func RecvmsgBuffers(fd int, buffers [][]byte, oob []byte, flags int) (n, oobn in
|
||||
}
|
||||
}
|
||||
var rsa RawSockaddrAny
|
||||
n, oobn, recvflags, err = recvmsgRaw(fd, iov, oob, flags, &rsa)
|
||||
if err == nil && rsa.Addr.Family != AF_UNSPEC {
|
||||
if n, oobn, recvflags, err = recvmsgRaw(fd, iov, oob, flags, &rsa); err != nil {
|
||||
return
|
||||
}
|
||||
if rsa.Addr.Family != AF_UNSPEC {
|
||||
from, err = anyToSockaddr(fd, &rsa)
|
||||
}
|
||||
return
|
||||
|
||||
+361
@@ -853,20 +853,86 @@ const (
|
||||
DM_VERSION_MAJOR = 0x4
|
||||
DM_VERSION_MINOR = 0x32
|
||||
DM_VERSION_PATCHLEVEL = 0x0
|
||||
DT_ADDRRNGHI = 0x6ffffeff
|
||||
DT_ADDRRNGLO = 0x6ffffe00
|
||||
DT_BLK = 0x6
|
||||
DT_CHR = 0x2
|
||||
DT_DEBUG = 0x15
|
||||
DT_DIR = 0x4
|
||||
DT_ENCODING = 0x20
|
||||
DT_FIFO = 0x1
|
||||
DT_FINI = 0xd
|
||||
DT_FLAGS_1 = 0x6ffffffb
|
||||
DT_GNU_HASH = 0x6ffffef5
|
||||
DT_HASH = 0x4
|
||||
DT_HIOS = 0x6ffff000
|
||||
DT_HIPROC = 0x7fffffff
|
||||
DT_INIT = 0xc
|
||||
DT_JMPREL = 0x17
|
||||
DT_LNK = 0xa
|
||||
DT_LOOS = 0x6000000d
|
||||
DT_LOPROC = 0x70000000
|
||||
DT_NEEDED = 0x1
|
||||
DT_NULL = 0x0
|
||||
DT_PLTGOT = 0x3
|
||||
DT_PLTREL = 0x14
|
||||
DT_PLTRELSZ = 0x2
|
||||
DT_REG = 0x8
|
||||
DT_REL = 0x11
|
||||
DT_RELA = 0x7
|
||||
DT_RELACOUNT = 0x6ffffff9
|
||||
DT_RELAENT = 0x9
|
||||
DT_RELASZ = 0x8
|
||||
DT_RELCOUNT = 0x6ffffffa
|
||||
DT_RELENT = 0x13
|
||||
DT_RELSZ = 0x12
|
||||
DT_RPATH = 0xf
|
||||
DT_SOCK = 0xc
|
||||
DT_SONAME = 0xe
|
||||
DT_STRSZ = 0xa
|
||||
DT_STRTAB = 0x5
|
||||
DT_SYMBOLIC = 0x10
|
||||
DT_SYMENT = 0xb
|
||||
DT_SYMTAB = 0x6
|
||||
DT_TEXTREL = 0x16
|
||||
DT_UNKNOWN = 0x0
|
||||
DT_VALRNGHI = 0x6ffffdff
|
||||
DT_VALRNGLO = 0x6ffffd00
|
||||
DT_VERDEF = 0x6ffffffc
|
||||
DT_VERDEFNUM = 0x6ffffffd
|
||||
DT_VERNEED = 0x6ffffffe
|
||||
DT_VERNEEDNUM = 0x6fffffff
|
||||
DT_VERSYM = 0x6ffffff0
|
||||
DT_WHT = 0xe
|
||||
ECHO = 0x8
|
||||
ECRYPTFS_SUPER_MAGIC = 0xf15f
|
||||
EFD_SEMAPHORE = 0x1
|
||||
EFIVARFS_MAGIC = 0xde5e81e4
|
||||
EFS_SUPER_MAGIC = 0x414a53
|
||||
EI_CLASS = 0x4
|
||||
EI_DATA = 0x5
|
||||
EI_MAG0 = 0x0
|
||||
EI_MAG1 = 0x1
|
||||
EI_MAG2 = 0x2
|
||||
EI_MAG3 = 0x3
|
||||
EI_NIDENT = 0x10
|
||||
EI_OSABI = 0x7
|
||||
EI_PAD = 0x8
|
||||
EI_VERSION = 0x6
|
||||
ELFCLASS32 = 0x1
|
||||
ELFCLASS64 = 0x2
|
||||
ELFCLASSNONE = 0x0
|
||||
ELFCLASSNUM = 0x3
|
||||
ELFDATA2LSB = 0x1
|
||||
ELFDATA2MSB = 0x2
|
||||
ELFDATANONE = 0x0
|
||||
ELFMAG = "\177ELF"
|
||||
ELFMAG0 = 0x7f
|
||||
ELFMAG1 = 'E'
|
||||
ELFMAG2 = 'L'
|
||||
ELFMAG3 = 'F'
|
||||
ELFOSABI_LINUX = 0x3
|
||||
ELFOSABI_NONE = 0x0
|
||||
EM_386 = 0x3
|
||||
EM_486 = 0x6
|
||||
EM_68K = 0x4
|
||||
@@ -1152,14 +1218,24 @@ const (
|
||||
ETH_P_WCCP = 0x883e
|
||||
ETH_P_X25 = 0x805
|
||||
ETH_P_XDSA = 0xf8
|
||||
ET_CORE = 0x4
|
||||
ET_DYN = 0x3
|
||||
ET_EXEC = 0x2
|
||||
ET_HIPROC = 0xffff
|
||||
ET_LOPROC = 0xff00
|
||||
ET_NONE = 0x0
|
||||
ET_REL = 0x1
|
||||
EV_ABS = 0x3
|
||||
EV_CNT = 0x20
|
||||
EV_CURRENT = 0x1
|
||||
EV_FF = 0x15
|
||||
EV_FF_STATUS = 0x17
|
||||
EV_KEY = 0x1
|
||||
EV_LED = 0x11
|
||||
EV_MAX = 0x1f
|
||||
EV_MSC = 0x4
|
||||
EV_NONE = 0x0
|
||||
EV_NUM = 0x2
|
||||
EV_PWR = 0x16
|
||||
EV_REL = 0x2
|
||||
EV_REP = 0x14
|
||||
@@ -1539,6 +1615,8 @@ const (
|
||||
IN_OPEN = 0x20
|
||||
IN_Q_OVERFLOW = 0x4000
|
||||
IN_UNMOUNT = 0x2000
|
||||
IOCTL_MEI_CONNECT_CLIENT = 0xc0104801
|
||||
IOCTL_MEI_CONNECT_CLIENT_VTAG = 0xc0144804
|
||||
IPPROTO_AH = 0x33
|
||||
IPPROTO_BEETPH = 0x5e
|
||||
IPPROTO_COMP = 0x6c
|
||||
@@ -2276,7 +2354,167 @@ const (
|
||||
NLM_F_REPLACE = 0x100
|
||||
NLM_F_REQUEST = 0x1
|
||||
NLM_F_ROOT = 0x100
|
||||
NN_386_IOPERM = "LINUX"
|
||||
NN_386_TLS = "LINUX"
|
||||
NN_ARC_V2 = "LINUX"
|
||||
NN_ARM_FPMR = "LINUX"
|
||||
NN_ARM_GCS = "LINUX"
|
||||
NN_ARM_HW_BREAK = "LINUX"
|
||||
NN_ARM_HW_WATCH = "LINUX"
|
||||
NN_ARM_PACA_KEYS = "LINUX"
|
||||
NN_ARM_PACG_KEYS = "LINUX"
|
||||
NN_ARM_PAC_ENABLED_KEYS = "LINUX"
|
||||
NN_ARM_PAC_MASK = "LINUX"
|
||||
NN_ARM_POE = "LINUX"
|
||||
NN_ARM_SSVE = "LINUX"
|
||||
NN_ARM_SVE = "LINUX"
|
||||
NN_ARM_SYSTEM_CALL = "LINUX"
|
||||
NN_ARM_TAGGED_ADDR_CTRL = "LINUX"
|
||||
NN_ARM_TLS = "LINUX"
|
||||
NN_ARM_VFP = "LINUX"
|
||||
NN_ARM_ZA = "LINUX"
|
||||
NN_ARM_ZT = "LINUX"
|
||||
NN_AUXV = "CORE"
|
||||
NN_FILE = "CORE"
|
||||
NN_GNU_PROPERTY_TYPE_0 = "GNU"
|
||||
NN_LOONGARCH_CPUCFG = "LINUX"
|
||||
NN_LOONGARCH_CSR = "LINUX"
|
||||
NN_LOONGARCH_HW_BREAK = "LINUX"
|
||||
NN_LOONGARCH_HW_WATCH = "LINUX"
|
||||
NN_LOONGARCH_LASX = "LINUX"
|
||||
NN_LOONGARCH_LBT = "LINUX"
|
||||
NN_LOONGARCH_LSX = "LINUX"
|
||||
NN_MIPS_DSP = "LINUX"
|
||||
NN_MIPS_FP_MODE = "LINUX"
|
||||
NN_MIPS_MSA = "LINUX"
|
||||
NN_PPC_DEXCR = "LINUX"
|
||||
NN_PPC_DSCR = "LINUX"
|
||||
NN_PPC_EBB = "LINUX"
|
||||
NN_PPC_HASHKEYR = "LINUX"
|
||||
NN_PPC_PKEY = "LINUX"
|
||||
NN_PPC_PMU = "LINUX"
|
||||
NN_PPC_PPR = "LINUX"
|
||||
NN_PPC_SPE = "LINUX"
|
||||
NN_PPC_TAR = "LINUX"
|
||||
NN_PPC_TM_CDSCR = "LINUX"
|
||||
NN_PPC_TM_CFPR = "LINUX"
|
||||
NN_PPC_TM_CGPR = "LINUX"
|
||||
NN_PPC_TM_CPPR = "LINUX"
|
||||
NN_PPC_TM_CTAR = "LINUX"
|
||||
NN_PPC_TM_CVMX = "LINUX"
|
||||
NN_PPC_TM_CVSX = "LINUX"
|
||||
NN_PPC_TM_SPR = "LINUX"
|
||||
NN_PPC_VMX = "LINUX"
|
||||
NN_PPC_VSX = "LINUX"
|
||||
NN_PRFPREG = "CORE"
|
||||
NN_PRPSINFO = "CORE"
|
||||
NN_PRSTATUS = "CORE"
|
||||
NN_PRXFPREG = "LINUX"
|
||||
NN_RISCV_CSR = "LINUX"
|
||||
NN_RISCV_TAGGED_ADDR_CTRL = "LINUX"
|
||||
NN_RISCV_VECTOR = "LINUX"
|
||||
NN_S390_CTRS = "LINUX"
|
||||
NN_S390_GS_BC = "LINUX"
|
||||
NN_S390_GS_CB = "LINUX"
|
||||
NN_S390_HIGH_GPRS = "LINUX"
|
||||
NN_S390_LAST_BREAK = "LINUX"
|
||||
NN_S390_PREFIX = "LINUX"
|
||||
NN_S390_PV_CPU_DATA = "LINUX"
|
||||
NN_S390_RI_CB = "LINUX"
|
||||
NN_S390_SYSTEM_CALL = "LINUX"
|
||||
NN_S390_TDB = "LINUX"
|
||||
NN_S390_TIMER = "LINUX"
|
||||
NN_S390_TODCMP = "LINUX"
|
||||
NN_S390_TODPREG = "LINUX"
|
||||
NN_S390_VXRS_HIGH = "LINUX"
|
||||
NN_S390_VXRS_LOW = "LINUX"
|
||||
NN_SIGINFO = "CORE"
|
||||
NN_TASKSTRUCT = "CORE"
|
||||
NN_VMCOREDD = "LINUX"
|
||||
NN_X86_SHSTK = "LINUX"
|
||||
NN_X86_XSAVE_LAYOUT = "LINUX"
|
||||
NN_X86_XSTATE = "LINUX"
|
||||
NSFS_MAGIC = 0x6e736673
|
||||
NT_386_IOPERM = 0x201
|
||||
NT_386_TLS = 0x200
|
||||
NT_ARC_V2 = 0x600
|
||||
NT_ARM_FPMR = 0x40e
|
||||
NT_ARM_GCS = 0x410
|
||||
NT_ARM_HW_BREAK = 0x402
|
||||
NT_ARM_HW_WATCH = 0x403
|
||||
NT_ARM_PACA_KEYS = 0x407
|
||||
NT_ARM_PACG_KEYS = 0x408
|
||||
NT_ARM_PAC_ENABLED_KEYS = 0x40a
|
||||
NT_ARM_PAC_MASK = 0x406
|
||||
NT_ARM_POE = 0x40f
|
||||
NT_ARM_SSVE = 0x40b
|
||||
NT_ARM_SVE = 0x405
|
||||
NT_ARM_SYSTEM_CALL = 0x404
|
||||
NT_ARM_TAGGED_ADDR_CTRL = 0x409
|
||||
NT_ARM_TLS = 0x401
|
||||
NT_ARM_VFP = 0x400
|
||||
NT_ARM_ZA = 0x40c
|
||||
NT_ARM_ZT = 0x40d
|
||||
NT_AUXV = 0x6
|
||||
NT_FILE = 0x46494c45
|
||||
NT_GNU_PROPERTY_TYPE_0 = 0x5
|
||||
NT_LOONGARCH_CPUCFG = 0xa00
|
||||
NT_LOONGARCH_CSR = 0xa01
|
||||
NT_LOONGARCH_HW_BREAK = 0xa05
|
||||
NT_LOONGARCH_HW_WATCH = 0xa06
|
||||
NT_LOONGARCH_LASX = 0xa03
|
||||
NT_LOONGARCH_LBT = 0xa04
|
||||
NT_LOONGARCH_LSX = 0xa02
|
||||
NT_MIPS_DSP = 0x800
|
||||
NT_MIPS_FP_MODE = 0x801
|
||||
NT_MIPS_MSA = 0x802
|
||||
NT_PPC_DEXCR = 0x111
|
||||
NT_PPC_DSCR = 0x105
|
||||
NT_PPC_EBB = 0x106
|
||||
NT_PPC_HASHKEYR = 0x112
|
||||
NT_PPC_PKEY = 0x110
|
||||
NT_PPC_PMU = 0x107
|
||||
NT_PPC_PPR = 0x104
|
||||
NT_PPC_SPE = 0x101
|
||||
NT_PPC_TAR = 0x103
|
||||
NT_PPC_TM_CDSCR = 0x10f
|
||||
NT_PPC_TM_CFPR = 0x109
|
||||
NT_PPC_TM_CGPR = 0x108
|
||||
NT_PPC_TM_CPPR = 0x10e
|
||||
NT_PPC_TM_CTAR = 0x10d
|
||||
NT_PPC_TM_CVMX = 0x10a
|
||||
NT_PPC_TM_CVSX = 0x10b
|
||||
NT_PPC_TM_SPR = 0x10c
|
||||
NT_PPC_VMX = 0x100
|
||||
NT_PPC_VSX = 0x102
|
||||
NT_PRFPREG = 0x2
|
||||
NT_PRPSINFO = 0x3
|
||||
NT_PRSTATUS = 0x1
|
||||
NT_PRXFPREG = 0x46e62b7f
|
||||
NT_RISCV_CSR = 0x900
|
||||
NT_RISCV_TAGGED_ADDR_CTRL = 0x902
|
||||
NT_RISCV_VECTOR = 0x901
|
||||
NT_S390_CTRS = 0x304
|
||||
NT_S390_GS_BC = 0x30c
|
||||
NT_S390_GS_CB = 0x30b
|
||||
NT_S390_HIGH_GPRS = 0x300
|
||||
NT_S390_LAST_BREAK = 0x306
|
||||
NT_S390_PREFIX = 0x305
|
||||
NT_S390_PV_CPU_DATA = 0x30e
|
||||
NT_S390_RI_CB = 0x30d
|
||||
NT_S390_SYSTEM_CALL = 0x307
|
||||
NT_S390_TDB = 0x308
|
||||
NT_S390_TIMER = 0x301
|
||||
NT_S390_TODCMP = 0x302
|
||||
NT_S390_TODPREG = 0x303
|
||||
NT_S390_VXRS_HIGH = 0x30a
|
||||
NT_S390_VXRS_LOW = 0x309
|
||||
NT_SIGINFO = 0x53494749
|
||||
NT_TASKSTRUCT = 0x4
|
||||
NT_VMCOREDD = 0x700
|
||||
NT_X86_SHSTK = 0x204
|
||||
NT_X86_XSAVE_LAYOUT = 0x205
|
||||
NT_X86_XSTATE = 0x202
|
||||
OCFS2_SUPER_MAGIC = 0x7461636f
|
||||
OCRNL = 0x8
|
||||
OFDEL = 0x80
|
||||
@@ -2463,6 +2701,59 @@ const (
|
||||
PERF_RECORD_MISC_USER = 0x2
|
||||
PERF_SAMPLE_BRANCH_PLM_ALL = 0x7
|
||||
PERF_SAMPLE_WEIGHT_TYPE = 0x1004000
|
||||
PF_ALG = 0x26
|
||||
PF_APPLETALK = 0x5
|
||||
PF_ASH = 0x12
|
||||
PF_ATMPVC = 0x8
|
||||
PF_ATMSVC = 0x14
|
||||
PF_AX25 = 0x3
|
||||
PF_BLUETOOTH = 0x1f
|
||||
PF_BRIDGE = 0x7
|
||||
PF_CAIF = 0x25
|
||||
PF_CAN = 0x1d
|
||||
PF_DECnet = 0xc
|
||||
PF_ECONET = 0x13
|
||||
PF_FILE = 0x1
|
||||
PF_IB = 0x1b
|
||||
PF_IEEE802154 = 0x24
|
||||
PF_INET = 0x2
|
||||
PF_INET6 = 0xa
|
||||
PF_IPX = 0x4
|
||||
PF_IRDA = 0x17
|
||||
PF_ISDN = 0x22
|
||||
PF_IUCV = 0x20
|
||||
PF_KCM = 0x29
|
||||
PF_KEY = 0xf
|
||||
PF_LLC = 0x1a
|
||||
PF_LOCAL = 0x1
|
||||
PF_MAX = 0x2e
|
||||
PF_MCTP = 0x2d
|
||||
PF_MPLS = 0x1c
|
||||
PF_NETBEUI = 0xd
|
||||
PF_NETLINK = 0x10
|
||||
PF_NETROM = 0x6
|
||||
PF_NFC = 0x27
|
||||
PF_PACKET = 0x11
|
||||
PF_PHONET = 0x23
|
||||
PF_PPPOX = 0x18
|
||||
PF_QIPCRTR = 0x2a
|
||||
PF_R = 0x4
|
||||
PF_RDS = 0x15
|
||||
PF_ROSE = 0xb
|
||||
PF_ROUTE = 0x10
|
||||
PF_RXRPC = 0x21
|
||||
PF_SECURITY = 0xe
|
||||
PF_SMC = 0x2b
|
||||
PF_SNA = 0x16
|
||||
PF_TIPC = 0x1e
|
||||
PF_UNIX = 0x1
|
||||
PF_UNSPEC = 0x0
|
||||
PF_VSOCK = 0x28
|
||||
PF_W = 0x2
|
||||
PF_WANPIPE = 0x19
|
||||
PF_X = 0x1
|
||||
PF_X25 = 0x9
|
||||
PF_XDP = 0x2c
|
||||
PID_FS_MAGIC = 0x50494446
|
||||
PIPEFS_MAGIC = 0x50495045
|
||||
PPPIOCGNPMODE = 0xc008744c
|
||||
@@ -2758,6 +3049,23 @@ const (
|
||||
PTRACE_SYSCALL_INFO_NONE = 0x0
|
||||
PTRACE_SYSCALL_INFO_SECCOMP = 0x3
|
||||
PTRACE_TRACEME = 0x0
|
||||
PT_AARCH64_MEMTAG_MTE = 0x70000002
|
||||
PT_DYNAMIC = 0x2
|
||||
PT_GNU_EH_FRAME = 0x6474e550
|
||||
PT_GNU_PROPERTY = 0x6474e553
|
||||
PT_GNU_RELRO = 0x6474e552
|
||||
PT_GNU_STACK = 0x6474e551
|
||||
PT_HIOS = 0x6fffffff
|
||||
PT_HIPROC = 0x7fffffff
|
||||
PT_INTERP = 0x3
|
||||
PT_LOAD = 0x1
|
||||
PT_LOOS = 0x60000000
|
||||
PT_LOPROC = 0x70000000
|
||||
PT_NOTE = 0x4
|
||||
PT_NULL = 0x0
|
||||
PT_PHDR = 0x6
|
||||
PT_SHLIB = 0x5
|
||||
PT_TLS = 0x7
|
||||
P_ALL = 0x0
|
||||
P_PGID = 0x2
|
||||
P_PID = 0x1
|
||||
@@ -3091,6 +3399,47 @@ const (
|
||||
SEEK_MAX = 0x4
|
||||
SEEK_SET = 0x0
|
||||
SELINUX_MAGIC = 0xf97cff8c
|
||||
SHF_ALLOC = 0x2
|
||||
SHF_EXCLUDE = 0x8000000
|
||||
SHF_EXECINSTR = 0x4
|
||||
SHF_GROUP = 0x200
|
||||
SHF_INFO_LINK = 0x40
|
||||
SHF_LINK_ORDER = 0x80
|
||||
SHF_MASKOS = 0xff00000
|
||||
SHF_MASKPROC = 0xf0000000
|
||||
SHF_MERGE = 0x10
|
||||
SHF_ORDERED = 0x4000000
|
||||
SHF_OS_NONCONFORMING = 0x100
|
||||
SHF_RELA_LIVEPATCH = 0x100000
|
||||
SHF_RO_AFTER_INIT = 0x200000
|
||||
SHF_STRINGS = 0x20
|
||||
SHF_TLS = 0x400
|
||||
SHF_WRITE = 0x1
|
||||
SHN_ABS = 0xfff1
|
||||
SHN_COMMON = 0xfff2
|
||||
SHN_HIPROC = 0xff1f
|
||||
SHN_HIRESERVE = 0xffff
|
||||
SHN_LIVEPATCH = 0xff20
|
||||
SHN_LOPROC = 0xff00
|
||||
SHN_LORESERVE = 0xff00
|
||||
SHN_UNDEF = 0x0
|
||||
SHT_DYNAMIC = 0x6
|
||||
SHT_DYNSYM = 0xb
|
||||
SHT_HASH = 0x5
|
||||
SHT_HIPROC = 0x7fffffff
|
||||
SHT_HIUSER = 0xffffffff
|
||||
SHT_LOPROC = 0x70000000
|
||||
SHT_LOUSER = 0x80000000
|
||||
SHT_NOBITS = 0x8
|
||||
SHT_NOTE = 0x7
|
||||
SHT_NULL = 0x0
|
||||
SHT_NUM = 0xc
|
||||
SHT_PROGBITS = 0x1
|
||||
SHT_REL = 0x9
|
||||
SHT_RELA = 0x4
|
||||
SHT_SHLIB = 0xa
|
||||
SHT_STRTAB = 0x3
|
||||
SHT_SYMTAB = 0x2
|
||||
SHUT_RD = 0x0
|
||||
SHUT_RDWR = 0x2
|
||||
SHUT_WR = 0x1
|
||||
@@ -3317,6 +3666,16 @@ const (
|
||||
STATX_UID = 0x8
|
||||
STATX_WRITE_ATOMIC = 0x10000
|
||||
STATX__RESERVED = 0x80000000
|
||||
STB_GLOBAL = 0x1
|
||||
STB_LOCAL = 0x0
|
||||
STB_WEAK = 0x2
|
||||
STT_COMMON = 0x5
|
||||
STT_FILE = 0x4
|
||||
STT_FUNC = 0x2
|
||||
STT_NOTYPE = 0x0
|
||||
STT_OBJECT = 0x1
|
||||
STT_SECTION = 0x3
|
||||
STT_TLS = 0x6
|
||||
SYNC_FILE_RANGE_WAIT_AFTER = 0x4
|
||||
SYNC_FILE_RANGE_WAIT_BEFORE = 0x1
|
||||
SYNC_FILE_RANGE_WRITE = 0x2
|
||||
@@ -3553,6 +3912,8 @@ const (
|
||||
UTIME_OMIT = 0x3ffffffe
|
||||
V9FS_MAGIC = 0x1021997
|
||||
VERASE = 0x2
|
||||
VER_FLG_BASE = 0x1
|
||||
VER_FLG_WEAK = 0x2
|
||||
VINTR = 0x0
|
||||
VKILL = 0x3
|
||||
VLNEXT = 0xf
|
||||
|
||||
+2
@@ -116,6 +116,8 @@ const (
|
||||
IEXTEN = 0x8000
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x80044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x40044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
|
||||
IPV6_FLOWINFO_MASK = 0xffffff0f
|
||||
IPV6_FLOWLABEL_MASK = 0xffff0f00
|
||||
|
||||
+2
@@ -116,6 +116,8 @@ const (
|
||||
IEXTEN = 0x8000
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x80044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x40044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
|
||||
IPV6_FLOWINFO_MASK = 0xffffff0f
|
||||
IPV6_FLOWLABEL_MASK = 0xffff0f00
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x8000
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x80044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x40044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
|
||||
IPV6_FLOWINFO_MASK = 0xffffff0f
|
||||
IPV6_FLOWLABEL_MASK = 0xffff0f00
|
||||
|
||||
+2
@@ -120,6 +120,8 @@ const (
|
||||
IEXTEN = 0x8000
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x80044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x40044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
|
||||
IPV6_FLOWINFO_MASK = 0xffffff0f
|
||||
IPV6_FLOWLABEL_MASK = 0xffff0f00
|
||||
|
||||
+2
@@ -116,6 +116,8 @@ const (
|
||||
IEXTEN = 0x8000
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x80044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x40044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
|
||||
IPV6_FLOWINFO_MASK = 0xffffff0f
|
||||
IPV6_FLOWLABEL_MASK = 0xffff0f00
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x100
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x80
|
||||
IOCTL_MEI_NOTIFY_GET = 0x40044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x80044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
|
||||
IPV6_FLOWINFO_MASK = 0xfffffff
|
||||
IPV6_FLOWLABEL_MASK = 0xfffff
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x100
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x80
|
||||
IOCTL_MEI_NOTIFY_GET = 0x40044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x80044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
|
||||
IPV6_FLOWINFO_MASK = 0xfffffff
|
||||
IPV6_FLOWLABEL_MASK = 0xfffff
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x100
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x80
|
||||
IOCTL_MEI_NOTIFY_GET = 0x40044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x80044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
|
||||
IPV6_FLOWINFO_MASK = 0xffffff0f
|
||||
IPV6_FLOWLABEL_MASK = 0xffff0f00
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x100
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x80
|
||||
IOCTL_MEI_NOTIFY_GET = 0x40044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x80044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
|
||||
IPV6_FLOWINFO_MASK = 0xffffff0f
|
||||
IPV6_FLOWLABEL_MASK = 0xffff0f00
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x400
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x40044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x80044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
|
||||
IPV6_FLOWINFO_MASK = 0xfffffff
|
||||
IPV6_FLOWLABEL_MASK = 0xfffff
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x400
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x40044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x80044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
|
||||
IPV6_FLOWINFO_MASK = 0xfffffff
|
||||
IPV6_FLOWLABEL_MASK = 0xfffff
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x400
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x40044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x80044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
|
||||
IPV6_FLOWINFO_MASK = 0xffffff0f
|
||||
IPV6_FLOWLABEL_MASK = 0xffff0f00
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x8000
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x80044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x40044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
|
||||
IPV6_FLOWINFO_MASK = 0xffffff0f
|
||||
IPV6_FLOWLABEL_MASK = 0xffff0f00
|
||||
|
||||
+2
@@ -115,6 +115,8 @@ const (
|
||||
IEXTEN = 0x8000
|
||||
IN_CLOEXEC = 0x80000
|
||||
IN_NONBLOCK = 0x800
|
||||
IOCTL_MEI_NOTIFY_GET = 0x80044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x40044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9
|
||||
IPV6_FLOWINFO_MASK = 0xfffffff
|
||||
IPV6_FLOWLABEL_MASK = 0xfffff
|
||||
|
||||
+2
@@ -119,6 +119,8 @@ const (
|
||||
IEXTEN = 0x8000
|
||||
IN_CLOEXEC = 0x400000
|
||||
IN_NONBLOCK = 0x4000
|
||||
IOCTL_MEI_NOTIFY_GET = 0x40044803
|
||||
IOCTL_MEI_NOTIFY_SET = 0x80044802
|
||||
IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9
|
||||
IPV6_FLOWINFO_MASK = 0xfffffff
|
||||
IPV6_FLOWLABEL_MASK = 0xfffff
|
||||
|
||||
+10
@@ -2238,3 +2238,13 @@ func Mseal(b []byte, flags uint) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func setMemPolicy(mode int, mask *CPUSet, size int) (err error) {
|
||||
_, _, e1 := Syscall(SYS_SET_MEMPOLICY, uintptr(mode), uintptr(unsafe.Pointer(mask)), uintptr(size))
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
+156
-104
@@ -593,110 +593,115 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
NDA_UNSPEC = 0x0
|
||||
NDA_DST = 0x1
|
||||
NDA_LLADDR = 0x2
|
||||
NDA_CACHEINFO = 0x3
|
||||
NDA_PROBES = 0x4
|
||||
NDA_VLAN = 0x5
|
||||
NDA_PORT = 0x6
|
||||
NDA_VNI = 0x7
|
||||
NDA_IFINDEX = 0x8
|
||||
NDA_MASTER = 0x9
|
||||
NDA_LINK_NETNSID = 0xa
|
||||
NDA_SRC_VNI = 0xb
|
||||
NTF_USE = 0x1
|
||||
NTF_SELF = 0x2
|
||||
NTF_MASTER = 0x4
|
||||
NTF_PROXY = 0x8
|
||||
NTF_EXT_LEARNED = 0x10
|
||||
NTF_OFFLOADED = 0x20
|
||||
NTF_ROUTER = 0x80
|
||||
NUD_INCOMPLETE = 0x1
|
||||
NUD_REACHABLE = 0x2
|
||||
NUD_STALE = 0x4
|
||||
NUD_DELAY = 0x8
|
||||
NUD_PROBE = 0x10
|
||||
NUD_FAILED = 0x20
|
||||
NUD_NOARP = 0x40
|
||||
NUD_PERMANENT = 0x80
|
||||
NUD_NONE = 0x0
|
||||
IFA_UNSPEC = 0x0
|
||||
IFA_ADDRESS = 0x1
|
||||
IFA_LOCAL = 0x2
|
||||
IFA_LABEL = 0x3
|
||||
IFA_BROADCAST = 0x4
|
||||
IFA_ANYCAST = 0x5
|
||||
IFA_CACHEINFO = 0x6
|
||||
IFA_MULTICAST = 0x7
|
||||
IFA_FLAGS = 0x8
|
||||
IFA_RT_PRIORITY = 0x9
|
||||
IFA_TARGET_NETNSID = 0xa
|
||||
IFAL_LABEL = 0x2
|
||||
IFAL_ADDRESS = 0x1
|
||||
RT_SCOPE_UNIVERSE = 0x0
|
||||
RT_SCOPE_SITE = 0xc8
|
||||
RT_SCOPE_LINK = 0xfd
|
||||
RT_SCOPE_HOST = 0xfe
|
||||
RT_SCOPE_NOWHERE = 0xff
|
||||
RT_TABLE_UNSPEC = 0x0
|
||||
RT_TABLE_COMPAT = 0xfc
|
||||
RT_TABLE_DEFAULT = 0xfd
|
||||
RT_TABLE_MAIN = 0xfe
|
||||
RT_TABLE_LOCAL = 0xff
|
||||
RT_TABLE_MAX = 0xffffffff
|
||||
RTA_UNSPEC = 0x0
|
||||
RTA_DST = 0x1
|
||||
RTA_SRC = 0x2
|
||||
RTA_IIF = 0x3
|
||||
RTA_OIF = 0x4
|
||||
RTA_GATEWAY = 0x5
|
||||
RTA_PRIORITY = 0x6
|
||||
RTA_PREFSRC = 0x7
|
||||
RTA_METRICS = 0x8
|
||||
RTA_MULTIPATH = 0x9
|
||||
RTA_FLOW = 0xb
|
||||
RTA_CACHEINFO = 0xc
|
||||
RTA_TABLE = 0xf
|
||||
RTA_MARK = 0x10
|
||||
RTA_MFC_STATS = 0x11
|
||||
RTA_VIA = 0x12
|
||||
RTA_NEWDST = 0x13
|
||||
RTA_PREF = 0x14
|
||||
RTA_ENCAP_TYPE = 0x15
|
||||
RTA_ENCAP = 0x16
|
||||
RTA_EXPIRES = 0x17
|
||||
RTA_PAD = 0x18
|
||||
RTA_UID = 0x19
|
||||
RTA_TTL_PROPAGATE = 0x1a
|
||||
RTA_IP_PROTO = 0x1b
|
||||
RTA_SPORT = 0x1c
|
||||
RTA_DPORT = 0x1d
|
||||
RTN_UNSPEC = 0x0
|
||||
RTN_UNICAST = 0x1
|
||||
RTN_LOCAL = 0x2
|
||||
RTN_BROADCAST = 0x3
|
||||
RTN_ANYCAST = 0x4
|
||||
RTN_MULTICAST = 0x5
|
||||
RTN_BLACKHOLE = 0x6
|
||||
RTN_UNREACHABLE = 0x7
|
||||
RTN_PROHIBIT = 0x8
|
||||
RTN_THROW = 0x9
|
||||
RTN_NAT = 0xa
|
||||
RTN_XRESOLVE = 0xb
|
||||
SizeofNlMsghdr = 0x10
|
||||
SizeofNlMsgerr = 0x14
|
||||
SizeofRtGenmsg = 0x1
|
||||
SizeofNlAttr = 0x4
|
||||
SizeofRtAttr = 0x4
|
||||
SizeofIfInfomsg = 0x10
|
||||
SizeofIfAddrmsg = 0x8
|
||||
SizeofIfAddrlblmsg = 0xc
|
||||
SizeofIfaCacheinfo = 0x10
|
||||
SizeofRtMsg = 0xc
|
||||
SizeofRtNexthop = 0x8
|
||||
SizeofNdUseroptmsg = 0x10
|
||||
SizeofNdMsg = 0xc
|
||||
NDA_UNSPEC = 0x0
|
||||
NDA_DST = 0x1
|
||||
NDA_LLADDR = 0x2
|
||||
NDA_CACHEINFO = 0x3
|
||||
NDA_PROBES = 0x4
|
||||
NDA_VLAN = 0x5
|
||||
NDA_PORT = 0x6
|
||||
NDA_VNI = 0x7
|
||||
NDA_IFINDEX = 0x8
|
||||
NDA_MASTER = 0x9
|
||||
NDA_LINK_NETNSID = 0xa
|
||||
NDA_SRC_VNI = 0xb
|
||||
NTF_USE = 0x1
|
||||
NTF_SELF = 0x2
|
||||
NTF_MASTER = 0x4
|
||||
NTF_PROXY = 0x8
|
||||
NTF_EXT_LEARNED = 0x10
|
||||
NTF_OFFLOADED = 0x20
|
||||
NTF_ROUTER = 0x80
|
||||
NUD_INCOMPLETE = 0x1
|
||||
NUD_REACHABLE = 0x2
|
||||
NUD_STALE = 0x4
|
||||
NUD_DELAY = 0x8
|
||||
NUD_PROBE = 0x10
|
||||
NUD_FAILED = 0x20
|
||||
NUD_NOARP = 0x40
|
||||
NUD_PERMANENT = 0x80
|
||||
NUD_NONE = 0x0
|
||||
IFA_UNSPEC = 0x0
|
||||
IFA_ADDRESS = 0x1
|
||||
IFA_LOCAL = 0x2
|
||||
IFA_LABEL = 0x3
|
||||
IFA_BROADCAST = 0x4
|
||||
IFA_ANYCAST = 0x5
|
||||
IFA_CACHEINFO = 0x6
|
||||
IFA_MULTICAST = 0x7
|
||||
IFA_FLAGS = 0x8
|
||||
IFA_RT_PRIORITY = 0x9
|
||||
IFA_TARGET_NETNSID = 0xa
|
||||
IFAL_LABEL = 0x2
|
||||
IFAL_ADDRESS = 0x1
|
||||
RT_SCOPE_UNIVERSE = 0x0
|
||||
RT_SCOPE_SITE = 0xc8
|
||||
RT_SCOPE_LINK = 0xfd
|
||||
RT_SCOPE_HOST = 0xfe
|
||||
RT_SCOPE_NOWHERE = 0xff
|
||||
RT_TABLE_UNSPEC = 0x0
|
||||
RT_TABLE_COMPAT = 0xfc
|
||||
RT_TABLE_DEFAULT = 0xfd
|
||||
RT_TABLE_MAIN = 0xfe
|
||||
RT_TABLE_LOCAL = 0xff
|
||||
RT_TABLE_MAX = 0xffffffff
|
||||
RTA_UNSPEC = 0x0
|
||||
RTA_DST = 0x1
|
||||
RTA_SRC = 0x2
|
||||
RTA_IIF = 0x3
|
||||
RTA_OIF = 0x4
|
||||
RTA_GATEWAY = 0x5
|
||||
RTA_PRIORITY = 0x6
|
||||
RTA_PREFSRC = 0x7
|
||||
RTA_METRICS = 0x8
|
||||
RTA_MULTIPATH = 0x9
|
||||
RTA_FLOW = 0xb
|
||||
RTA_CACHEINFO = 0xc
|
||||
RTA_TABLE = 0xf
|
||||
RTA_MARK = 0x10
|
||||
RTA_MFC_STATS = 0x11
|
||||
RTA_VIA = 0x12
|
||||
RTA_NEWDST = 0x13
|
||||
RTA_PREF = 0x14
|
||||
RTA_ENCAP_TYPE = 0x15
|
||||
RTA_ENCAP = 0x16
|
||||
RTA_EXPIRES = 0x17
|
||||
RTA_PAD = 0x18
|
||||
RTA_UID = 0x19
|
||||
RTA_TTL_PROPAGATE = 0x1a
|
||||
RTA_IP_PROTO = 0x1b
|
||||
RTA_SPORT = 0x1c
|
||||
RTA_DPORT = 0x1d
|
||||
RTN_UNSPEC = 0x0
|
||||
RTN_UNICAST = 0x1
|
||||
RTN_LOCAL = 0x2
|
||||
RTN_BROADCAST = 0x3
|
||||
RTN_ANYCAST = 0x4
|
||||
RTN_MULTICAST = 0x5
|
||||
RTN_BLACKHOLE = 0x6
|
||||
RTN_UNREACHABLE = 0x7
|
||||
RTN_PROHIBIT = 0x8
|
||||
RTN_THROW = 0x9
|
||||
RTN_NAT = 0xa
|
||||
RTN_XRESOLVE = 0xb
|
||||
PREFIX_UNSPEC = 0x0
|
||||
PREFIX_ADDRESS = 0x1
|
||||
PREFIX_CACHEINFO = 0x2
|
||||
SizeofNlMsghdr = 0x10
|
||||
SizeofNlMsgerr = 0x14
|
||||
SizeofRtGenmsg = 0x1
|
||||
SizeofNlAttr = 0x4
|
||||
SizeofRtAttr = 0x4
|
||||
SizeofIfInfomsg = 0x10
|
||||
SizeofPrefixmsg = 0xc
|
||||
SizeofPrefixCacheinfo = 0x8
|
||||
SizeofIfAddrmsg = 0x8
|
||||
SizeofIfAddrlblmsg = 0xc
|
||||
SizeofIfaCacheinfo = 0x10
|
||||
SizeofRtMsg = 0xc
|
||||
SizeofRtNexthop = 0x8
|
||||
SizeofNdUseroptmsg = 0x10
|
||||
SizeofNdMsg = 0xc
|
||||
)
|
||||
|
||||
type NlMsghdr struct {
|
||||
@@ -735,6 +740,22 @@ type IfInfomsg struct {
|
||||
Change uint32
|
||||
}
|
||||
|
||||
type Prefixmsg struct {
|
||||
Family uint8
|
||||
Pad1 uint8
|
||||
Pad2 uint16
|
||||
Ifindex int32
|
||||
Type uint8
|
||||
Len uint8
|
||||
Flags uint8
|
||||
Pad3 uint8
|
||||
}
|
||||
|
||||
type PrefixCacheinfo struct {
|
||||
Preferred_time uint32
|
||||
Valid_time uint32
|
||||
}
|
||||
|
||||
type IfAddrmsg struct {
|
||||
Family uint8
|
||||
Prefixlen uint8
|
||||
@@ -3590,6 +3611,8 @@ type Nhmsg struct {
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
const SizeofNhmsg = 0x8
|
||||
|
||||
type NexthopGrp struct {
|
||||
Id uint32
|
||||
Weight uint8
|
||||
@@ -3597,6 +3620,8 @@ type NexthopGrp struct {
|
||||
Resvd2 uint16
|
||||
}
|
||||
|
||||
const SizeofNexthopGrp = 0x8
|
||||
|
||||
const (
|
||||
NHA_UNSPEC = 0x0
|
||||
NHA_ID = 0x1
|
||||
@@ -6332,3 +6357,30 @@ type SockDiagReq struct {
|
||||
}
|
||||
|
||||
const RTM_NEWNVLAN = 0x70
|
||||
|
||||
const (
|
||||
MPOL_BIND = 0x2
|
||||
MPOL_DEFAULT = 0x0
|
||||
MPOL_F_ADDR = 0x2
|
||||
MPOL_F_MEMS_ALLOWED = 0x4
|
||||
MPOL_F_MOF = 0x8
|
||||
MPOL_F_MORON = 0x10
|
||||
MPOL_F_NODE = 0x1
|
||||
MPOL_F_NUMA_BALANCING = 0x2000
|
||||
MPOL_F_RELATIVE_NODES = 0x4000
|
||||
MPOL_F_SHARED = 0x1
|
||||
MPOL_F_STATIC_NODES = 0x8000
|
||||
MPOL_INTERLEAVE = 0x3
|
||||
MPOL_LOCAL = 0x4
|
||||
MPOL_MAX = 0x7
|
||||
MPOL_MF_INTERNAL = 0x10
|
||||
MPOL_MF_LAZY = 0x8
|
||||
MPOL_MF_MOVE_ALL = 0x4
|
||||
MPOL_MF_MOVE = 0x2
|
||||
MPOL_MF_STRICT = 0x1
|
||||
MPOL_MF_VALID = 0x7
|
||||
MPOL_MODE_FLAGS = 0xe000
|
||||
MPOL_PREFERRED = 0x1
|
||||
MPOL_PREFERRED_MANY = 0x5
|
||||
MPOL_WEIGHTED_INTERLEAVE = 0x6
|
||||
)
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ type Statvfs_t struct {
|
||||
Fsid uint32
|
||||
Namemax uint32
|
||||
Owner uint32
|
||||
Spare [4]uint32
|
||||
Spare [4]uint64
|
||||
Fstypename [32]byte
|
||||
Mntonname [1024]byte
|
||||
Mntfromname [1024]byte
|
||||
|
||||
+1
@@ -8,5 +8,6 @@ package windows
|
||||
|
||||
import "syscall"
|
||||
|
||||
type Signal = syscall.Signal
|
||||
type Errno = syscall.Errno
|
||||
type SysProcAttr = syscall.SysProcAttr
|
||||
|
||||
+16
-14
@@ -892,10 +892,15 @@ const socket_error = uintptr(^uint32(0))
|
||||
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
|
||||
//sys getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcode error) = iphlpapi.GetBestInterfaceEx
|
||||
//sys GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) = iphlpapi.GetIfEntry2Ex
|
||||
//sys GetIpForwardEntry2(row *MibIpForwardRow2) (errcode error) = iphlpapi.GetIpForwardEntry2
|
||||
//sys GetIpForwardTable2(family uint16, table **MibIpForwardTable2) (errcode error) = iphlpapi.GetIpForwardTable2
|
||||
//sys GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) = iphlpapi.GetUnicastIpAddressEntry
|
||||
//sys FreeMibTable(memory unsafe.Pointer) = iphlpapi.FreeMibTable
|
||||
//sys NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyIpInterfaceChange
|
||||
//sys NotifyRouteChange2(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyRouteChange2
|
||||
//sys NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyUnicastIpAddressChange
|
||||
//sys CancelMibChangeNotify2(notificationHandle Handle) (errcode error) = iphlpapi.CancelMibChangeNotify2
|
||||
//sys IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) = kernel32.IsProcessorFeaturePresent
|
||||
|
||||
// For testing: clients can set this flag to force
|
||||
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||
@@ -916,6 +921,17 @@ type RawSockaddrInet6 struct {
|
||||
Scope_id uint32
|
||||
}
|
||||
|
||||
// RawSockaddrInet is a union that contains an IPv4, an IPv6 address, or an address family. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-sockaddr_inet.
|
||||
//
|
||||
// A [*RawSockaddrInet] may be converted to a [*RawSockaddrInet4] or [*RawSockaddrInet6] using
|
||||
// unsafe, depending on the address family.
|
||||
type RawSockaddrInet struct {
|
||||
Family uint16
|
||||
Port uint16
|
||||
Data [6]uint32
|
||||
}
|
||||
|
||||
type RawSockaddr struct {
|
||||
Family uint16
|
||||
Data [14]int8
|
||||
@@ -1474,20 +1490,6 @@ func Getgid() (gid int) { return -1 }
|
||||
func Getegid() (egid int) { return -1 }
|
||||
func Getgroups() (gids []int, err error) { return nil, syscall.EWINDOWS }
|
||||
|
||||
type Signal int
|
||||
|
||||
func (s Signal) Signal() {}
|
||||
|
||||
func (s Signal) String() string {
|
||||
if 0 <= s && int(s) < len(signals) {
|
||||
str := signals[s]
|
||||
if str != "" {
|
||||
return str
|
||||
}
|
||||
}
|
||||
return "signal " + itoa(int(s))
|
||||
}
|
||||
|
||||
func LoadCreateSymbolicLink() error {
|
||||
return procCreateSymbolicLinkW.Find()
|
||||
}
|
||||
|
||||
+161
@@ -2320,6 +2320,82 @@ type MibIfRow2 struct {
|
||||
OutQLen uint64
|
||||
}
|
||||
|
||||
// IP_ADDRESS_PREFIX stores an IP address prefix. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-ip_address_prefix.
|
||||
type IpAddressPrefix struct {
|
||||
Prefix RawSockaddrInet
|
||||
PrefixLength uint8
|
||||
}
|
||||
|
||||
// NL_ROUTE_ORIGIN enumeration from nldef.h or
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_route_origin.
|
||||
const (
|
||||
NlroManual = 0
|
||||
NlroWellKnown = 1
|
||||
NlroDHCP = 2
|
||||
NlroRouterAdvertisement = 3
|
||||
Nlro6to4 = 4
|
||||
)
|
||||
|
||||
// NL_ROUTE_ORIGIN enumeration from nldef.h or
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_route_protocol.
|
||||
const (
|
||||
MIB_IPPROTO_OTHER = 1
|
||||
MIB_IPPROTO_LOCAL = 2
|
||||
MIB_IPPROTO_NETMGMT = 3
|
||||
MIB_IPPROTO_ICMP = 4
|
||||
MIB_IPPROTO_EGP = 5
|
||||
MIB_IPPROTO_GGP = 6
|
||||
MIB_IPPROTO_HELLO = 7
|
||||
MIB_IPPROTO_RIP = 8
|
||||
MIB_IPPROTO_IS_IS = 9
|
||||
MIB_IPPROTO_ES_IS = 10
|
||||
MIB_IPPROTO_CISCO = 11
|
||||
MIB_IPPROTO_BBN = 12
|
||||
MIB_IPPROTO_OSPF = 13
|
||||
MIB_IPPROTO_BGP = 14
|
||||
MIB_IPPROTO_IDPR = 15
|
||||
MIB_IPPROTO_EIGRP = 16
|
||||
MIB_IPPROTO_DVMRP = 17
|
||||
MIB_IPPROTO_RPL = 18
|
||||
MIB_IPPROTO_DHCP = 19
|
||||
MIB_IPPROTO_NT_AUTOSTATIC = 10002
|
||||
MIB_IPPROTO_NT_STATIC = 10006
|
||||
MIB_IPPROTO_NT_STATIC_NON_DOD = 10007
|
||||
)
|
||||
|
||||
// MIB_IPFORWARD_ROW2 stores information about an IP route entry. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipforward_row2.
|
||||
type MibIpForwardRow2 struct {
|
||||
InterfaceLuid uint64
|
||||
InterfaceIndex uint32
|
||||
DestinationPrefix IpAddressPrefix
|
||||
NextHop RawSockaddrInet
|
||||
SitePrefixLength uint8
|
||||
ValidLifetime uint32
|
||||
PreferredLifetime uint32
|
||||
Metric uint32
|
||||
Protocol uint32
|
||||
Loopback uint8
|
||||
AutoconfigureAddress uint8
|
||||
Publish uint8
|
||||
Immortal uint8
|
||||
Age uint32
|
||||
Origin uint32
|
||||
}
|
||||
|
||||
// MIB_IPFORWARD_TABLE2 contains a table of IP route entries. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipforward_table2.
|
||||
type MibIpForwardTable2 struct {
|
||||
NumEntries uint32
|
||||
Table [1]MibIpForwardRow2
|
||||
}
|
||||
|
||||
// Rows returns the IP route entries in the table.
|
||||
func (t *MibIpForwardTable2) Rows() []MibIpForwardRow2 {
|
||||
return unsafe.Slice(&t.Table[0], t.NumEntries)
|
||||
}
|
||||
|
||||
// MIB_UNICASTIPADDRESS_ROW stores information about a unicast IP address. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_unicastipaddress_row.
|
||||
type MibUnicastIpAddressRow struct {
|
||||
@@ -3862,3 +3938,88 @@ const (
|
||||
MOUSE_EVENT = 0x0002
|
||||
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||
)
|
||||
|
||||
// The processor features to be tested for IsProcessorFeaturePresent, see
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
|
||||
const (
|
||||
PF_ARM_64BIT_LOADSTORE_ATOMIC = 25
|
||||
PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE = 24
|
||||
PF_ARM_EXTERNAL_CACHE_AVAILABLE = 26
|
||||
PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE = 27
|
||||
PF_ARM_VFP_32_REGISTERS_AVAILABLE = 18
|
||||
PF_3DNOW_INSTRUCTIONS_AVAILABLE = 7
|
||||
PF_CHANNELS_ENABLED = 16
|
||||
PF_COMPARE_EXCHANGE_DOUBLE = 2
|
||||
PF_COMPARE_EXCHANGE128 = 14
|
||||
PF_COMPARE64_EXCHANGE128 = 15
|
||||
PF_FASTFAIL_AVAILABLE = 23
|
||||
PF_FLOATING_POINT_EMULATED = 1
|
||||
PF_FLOATING_POINT_PRECISION_ERRATA = 0
|
||||
PF_MMX_INSTRUCTIONS_AVAILABLE = 3
|
||||
PF_NX_ENABLED = 12
|
||||
PF_PAE_ENABLED = 9
|
||||
PF_RDTSC_INSTRUCTION_AVAILABLE = 8
|
||||
PF_RDWRFSGSBASE_AVAILABLE = 22
|
||||
PF_SECOND_LEVEL_ADDRESS_TRANSLATION = 20
|
||||
PF_SSE3_INSTRUCTIONS_AVAILABLE = 13
|
||||
PF_SSSE3_INSTRUCTIONS_AVAILABLE = 36
|
||||
PF_SSE4_1_INSTRUCTIONS_AVAILABLE = 37
|
||||
PF_SSE4_2_INSTRUCTIONS_AVAILABLE = 38
|
||||
PF_AVX_INSTRUCTIONS_AVAILABLE = 39
|
||||
PF_AVX2_INSTRUCTIONS_AVAILABLE = 40
|
||||
PF_AVX512F_INSTRUCTIONS_AVAILABLE = 41
|
||||
PF_VIRT_FIRMWARE_ENABLED = 21
|
||||
PF_XMMI_INSTRUCTIONS_AVAILABLE = 6
|
||||
PF_XMMI64_INSTRUCTIONS_AVAILABLE = 10
|
||||
PF_XSAVE_ENABLED = 17
|
||||
PF_ARM_V8_INSTRUCTIONS_AVAILABLE = 29
|
||||
PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30
|
||||
PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31
|
||||
PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34
|
||||
PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE = 43
|
||||
PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44
|
||||
PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE = 45
|
||||
PF_ARM_SVE_INSTRUCTIONS_AVAILABLE = 46
|
||||
PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE = 47
|
||||
PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE = 48
|
||||
PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE = 49
|
||||
PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE = 50
|
||||
PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE = 51
|
||||
PF_ARM_SVE_BF16_INSTRUCTIONS_AVAILABLE = 52
|
||||
PF_ARM_SVE_EBF16_INSTRUCTIONS_AVAILABLE = 53
|
||||
PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE = 54
|
||||
PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE = 55
|
||||
PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE = 56
|
||||
PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE = 57
|
||||
PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE = 58
|
||||
PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE = 59
|
||||
PF_BMI2_INSTRUCTIONS_AVAILABLE = 60
|
||||
PF_MOVDIR64B_INSTRUCTION_AVAILABLE = 61
|
||||
PF_ARM_LSE2_AVAILABLE = 62
|
||||
PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE = 64
|
||||
PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE = 65
|
||||
PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE = 66
|
||||
PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE = 67
|
||||
PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE = 68
|
||||
PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE = 69
|
||||
PF_ARM_SME_INSTRUCTIONS_AVAILABLE = 70
|
||||
PF_ARM_SME2_INSTRUCTIONS_AVAILABLE = 71
|
||||
PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE = 72
|
||||
PF_ARM_SME2_2_INSTRUCTIONS_AVAILABLE = 73
|
||||
PF_ARM_SME_AES_INSTRUCTIONS_AVAILABLE = 74
|
||||
PF_ARM_SME_SBITPERM_INSTRUCTIONS_AVAILABLE = 75
|
||||
PF_ARM_SME_SF8MM4_INSTRUCTIONS_AVAILABLE = 76
|
||||
PF_ARM_SME_SF8MM8_INSTRUCTIONS_AVAILABLE = 77
|
||||
PF_ARM_SME_SF8DP2_INSTRUCTIONS_AVAILABLE = 78
|
||||
PF_ARM_SME_SF8DP4_INSTRUCTIONS_AVAILABLE = 79
|
||||
PF_ARM_SME_SF8FMA_INSTRUCTIONS_AVAILABLE = 80
|
||||
PF_ARM_SME_F8F32_INSTRUCTIONS_AVAILABLE = 81
|
||||
PF_ARM_SME_F8F16_INSTRUCTIONS_AVAILABLE = 82
|
||||
PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE = 83
|
||||
PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE = 84
|
||||
PF_ARM_SME_F64F64_INSTRUCTIONS_AVAILABLE = 85
|
||||
PF_ARM_SME_I16I64_INSTRUCTIONS_AVAILABLE = 86
|
||||
PF_ARM_SME_LUTv2_INSTRUCTIONS_AVAILABLE = 87
|
||||
PF_ARM_SME_FA64_INSTRUCTIONS_AVAILABLE = 88
|
||||
PF_UMONITOR_INSTRUCTION_AVAILABLE = 89
|
||||
)
|
||||
|
||||
+44
@@ -182,13 +182,17 @@ var (
|
||||
procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute")
|
||||
procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
|
||||
procCancelMibChangeNotify2 = modiphlpapi.NewProc("CancelMibChangeNotify2")
|
||||
procFreeMibTable = modiphlpapi.NewProc("FreeMibTable")
|
||||
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
|
||||
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
|
||||
procGetBestInterfaceEx = modiphlpapi.NewProc("GetBestInterfaceEx")
|
||||
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
||||
procGetIfEntry2Ex = modiphlpapi.NewProc("GetIfEntry2Ex")
|
||||
procGetIpForwardEntry2 = modiphlpapi.NewProc("GetIpForwardEntry2")
|
||||
procGetIpForwardTable2 = modiphlpapi.NewProc("GetIpForwardTable2")
|
||||
procGetUnicastIpAddressEntry = modiphlpapi.NewProc("GetUnicastIpAddressEntry")
|
||||
procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange")
|
||||
procNotifyRouteChange2 = modiphlpapi.NewProc("NotifyRouteChange2")
|
||||
procNotifyUnicastIpAddressChange = modiphlpapi.NewProc("NotifyUnicastIpAddressChange")
|
||||
procAddDllDirectory = modkernel32.NewProc("AddDllDirectory")
|
||||
procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject")
|
||||
@@ -316,6 +320,7 @@ var (
|
||||
procGetVolumePathNamesForVolumeNameW = modkernel32.NewProc("GetVolumePathNamesForVolumeNameW")
|
||||
procGetWindowsDirectoryW = modkernel32.NewProc("GetWindowsDirectoryW")
|
||||
procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList")
|
||||
procIsProcessorFeaturePresent = modkernel32.NewProc("IsProcessorFeaturePresent")
|
||||
procIsWow64Process = modkernel32.NewProc("IsWow64Process")
|
||||
procIsWow64Process2 = modkernel32.NewProc("IsWow64Process2")
|
||||
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
|
||||
@@ -1624,6 +1629,11 @@ func CancelMibChangeNotify2(notificationHandle Handle) (errcode error) {
|
||||
return
|
||||
}
|
||||
|
||||
func FreeMibTable(memory unsafe.Pointer) {
|
||||
syscall.SyscallN(procFreeMibTable.Addr(), uintptr(memory))
|
||||
return
|
||||
}
|
||||
|
||||
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
|
||||
r0, _, _ := syscall.SyscallN(procGetAdaptersAddresses.Addr(), uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)))
|
||||
if r0 != 0 {
|
||||
@@ -1664,6 +1674,22 @@ func GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) {
|
||||
return
|
||||
}
|
||||
|
||||
func GetIpForwardEntry2(row *MibIpForwardRow2) (errcode error) {
|
||||
r0, _, _ := syscall.SyscallN(procGetIpForwardEntry2.Addr(), uintptr(unsafe.Pointer(row)))
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetIpForwardTable2(family uint16, table **MibIpForwardTable2) (errcode error) {
|
||||
r0, _, _ := syscall.SyscallN(procGetIpForwardTable2.Addr(), uintptr(family), uintptr(unsafe.Pointer(table)))
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) {
|
||||
r0, _, _ := syscall.SyscallN(procGetUnicastIpAddressEntry.Addr(), uintptr(unsafe.Pointer(row)))
|
||||
if r0 != 0 {
|
||||
@@ -1684,6 +1710,18 @@ func NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsa
|
||||
return
|
||||
}
|
||||
|
||||
func NotifyRouteChange2(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
|
||||
var _p0 uint32
|
||||
if initialNotification {
|
||||
_p0 = 1
|
||||
}
|
||||
r0, _, _ := syscall.SyscallN(procNotifyRouteChange2.Addr(), uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)))
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
|
||||
var _p0 uint32
|
||||
if initialNotification {
|
||||
@@ -2749,6 +2787,12 @@ func initializeProcThreadAttributeList(attrlist *ProcThreadAttributeList, attrco
|
||||
return
|
||||
}
|
||||
|
||||
func IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) {
|
||||
r0, _, _ := syscall.SyscallN(procIsProcessorFeaturePresent.Addr(), uintptr(ProcessorFeature))
|
||||
ret = r0 != 0
|
||||
return
|
||||
}
|
||||
|
||||
func IsWow64Process(handle Handle, isWow64 *bool) (err error) {
|
||||
var _p0 uint32
|
||||
if *isWow64 {
|
||||
|
||||
-2255
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user