mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-02 19:57:35 +03:00
116 lines
2.7 KiB
Go
116 lines
2.7 KiB
Go
package protocol
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
var ErrInvalidConnectionIDLen = errors.New("invalid Connection ID length")
|
|
|
|
// An ArbitraryLenConnectionID is a QUIC Connection ID able to represent Connection IDs according to RFC 8999.
|
|
// Future QUIC versions might allow connection ID lengths up to 255 bytes, while QUIC v1
|
|
// restricts the length to 20 bytes.
|
|
type ArbitraryLenConnectionID []byte
|
|
|
|
func (c ArbitraryLenConnectionID) Len() int {
|
|
return len(c)
|
|
}
|
|
|
|
func (c ArbitraryLenConnectionID) Bytes() []byte {
|
|
return c
|
|
}
|
|
|
|
func (c ArbitraryLenConnectionID) String() string {
|
|
if c.Len() == 0 {
|
|
return "(empty)"
|
|
}
|
|
return fmt.Sprintf("%x", c.Bytes())
|
|
}
|
|
|
|
const maxConnectionIDLen = 20
|
|
|
|
// A ConnectionID in QUIC
|
|
type ConnectionID struct {
|
|
b [20]byte
|
|
l uint8
|
|
}
|
|
|
|
// GenerateConnectionID generates a connection ID using cryptographic random
|
|
func GenerateConnectionID(l int) (ConnectionID, error) {
|
|
var c ConnectionID
|
|
c.l = uint8(l)
|
|
_, err := rand.Read(c.b[:l])
|
|
return c, err
|
|
}
|
|
|
|
// ParseConnectionID interprets b as a Connection ID.
|
|
// It panics if b is longer than 20 bytes.
|
|
func ParseConnectionID(b []byte) ConnectionID {
|
|
if len(b) > maxConnectionIDLen {
|
|
panic("invalid conn id length")
|
|
}
|
|
var c ConnectionID
|
|
c.l = uint8(len(b))
|
|
copy(c.b[:c.l], b)
|
|
return c
|
|
}
|
|
|
|
// GenerateConnectionIDForInitial generates a connection ID for the Initial packet.
|
|
// It uses a length randomly chosen between 8 and 20 bytes.
|
|
func GenerateConnectionIDForInitial() (ConnectionID, error) {
|
|
r := make([]byte, 1)
|
|
if _, err := rand.Read(r); err != nil {
|
|
return ConnectionID{}, err
|
|
}
|
|
l := MinConnectionIDLenInitial + int(r[0])%(maxConnectionIDLen-MinConnectionIDLenInitial+1)
|
|
return GenerateConnectionID(l)
|
|
}
|
|
|
|
// ReadConnectionID reads a connection ID of length len from the given io.Reader.
|
|
// It returns io.EOF if there are not enough bytes to read.
|
|
func ReadConnectionID(r io.Reader, l int) (ConnectionID, error) {
|
|
var c ConnectionID
|
|
if l == 0 {
|
|
return c, nil
|
|
}
|
|
if l > maxConnectionIDLen {
|
|
return c, ErrInvalidConnectionIDLen
|
|
}
|
|
c.l = uint8(l)
|
|
_, err := io.ReadFull(r, c.b[:l])
|
|
if err == io.ErrUnexpectedEOF {
|
|
return c, io.EOF
|
|
}
|
|
return c, err
|
|
}
|
|
|
|
// Len returns the length of the connection ID in bytes
|
|
func (c ConnectionID) Len() int {
|
|
return int(c.l)
|
|
}
|
|
|
|
// Bytes returns the byte representation
|
|
func (c ConnectionID) Bytes() []byte {
|
|
return c.b[:c.l]
|
|
}
|
|
|
|
func (c ConnectionID) String() string {
|
|
if c.Len() == 0 {
|
|
return "(empty)"
|
|
}
|
|
return fmt.Sprintf("%x", c.Bytes())
|
|
}
|
|
|
|
type DefaultConnectionIDGenerator struct {
|
|
ConnLen int
|
|
}
|
|
|
|
func (d *DefaultConnectionIDGenerator) GenerateConnectionID() (ConnectionID, error) {
|
|
return GenerateConnectionID(d.ConnLen)
|
|
}
|
|
|
|
func (d *DefaultConnectionIDGenerator) ConnectionIDLen() int {
|
|
return d.ConnLen
|
|
}
|