File: connection_id.go

package info (click to toggle)
golang-github-lucas-clemente-quic-go 0.54.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,312 kB
  • sloc: sh: 54; makefile: 7
file content (116 lines) | stat: -rw-r--r-- 2,782 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
}