package protocol
import (
"crypto/rand"
"encoding/binary"
"fmt"
"math"
mrand "math/rand/v2"
"slices"
"sync"
)
type Version uint32
const (
gquicVersion0 = 0x51303030
maxGquicVersion = 0x51303439
)
const (
VersionUnknown Version = math .MaxUint32
versionDraft29 Version = 0xff00001d
Version1 Version = 0x1
Version2 Version = 0x6b3343cf
)
var SupportedVersions = []Version {Version1 , Version2 }
func IsValidVersion (v Version ) bool {
return v == Version1 || IsSupportedVersion (SupportedVersions , v )
}
func (vn Version ) String () string {
switch vn {
case VersionUnknown :
return "unknown"
case versionDraft29 :
return "draft-29"
case Version1 :
return "v1"
case Version2 :
return "v2"
default :
if vn .isGQUIC () {
return fmt .Sprintf ("gQUIC %d" , vn .toGQUICVersion ())
}
return fmt .Sprintf ("%#x" , uint32 (vn ))
}
}
func (vn Version ) isGQUIC () bool {
return vn > gquicVersion0 && vn <= maxGquicVersion
}
func (vn Version ) toGQUICVersion () int {
return int (10 *(vn -gquicVersion0 )/0x100 ) + int (vn %0x10 )
}
func IsSupportedVersion (supported []Version , v Version ) bool {
return slices .Contains (supported , v )
}
func ChooseSupportedVersion (ours , theirs []Version ) (Version , bool ) {
for _ , ourVer := range ours {
if slices .Contains (theirs , ourVer ) {
return ourVer , true
}
}
return 0 , false
}
var (
versionNegotiationMx sync .Mutex
versionNegotiationRand mrand .Rand
)
func init() {
var seed [16 ]byte
rand .Read (seed [:])
versionNegotiationRand = *mrand .New (mrand .NewPCG (
binary .BigEndian .Uint64 (seed [:8 ]),
binary .BigEndian .Uint64 (seed [8 :]),
))
}
func generateReservedVersion() Version {
var b [4 ]byte
binary .BigEndian .PutUint32 (b [:], versionNegotiationRand .Uint32 ())
return Version ((binary .BigEndian .Uint32 (b [:]) | 0x0a0a0a0a ) & 0xfafafafa )
}
func GetGreasedVersions (supported []Version ) []Version {
versionNegotiationMx .Lock ()
defer versionNegotiationMx .Unlock ()
randPos := versionNegotiationRand .IntN (len (supported ) + 1 )
greased := make ([]Version , len (supported )+1 )
copy (greased , supported [:randPos ])
greased [randPos ] = generateReservedVersion ()
copy (greased [randPos +1 :], supported [randPos :])
return greased
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .