Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge upstream v0.29.0 #25

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
20 changes: 0 additions & 20 deletions .github/workflows/build-interop-docker.yml

This file was deleted.

23 changes: 0 additions & 23 deletions .github/workflows/cross-compile.sh

This file was deleted.

24 changes: 0 additions & 24 deletions .github/workflows/no_ginkgo.sh

This file was deleted.

43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
This is a private fork. To use, clone this repository as `$GOPATH/github.com/lucas-clemente/quic-go`
and perform the following additional setup locally:

```
git remote add upstream [email protected]:lucas-clemente/quic-go.git
git remote set-url --push upstream DISABLE
```

To take upstream changes (into master for example):

** Make sure to push a tag with the current master before executing a rebase to preserve any
references pointed at the current commit.

```
git fetch upstream
git tag snapshot_<version>
git push origin --tags
git rebase upstream/master
...
```

*Help!* I rebased and now something is complaining about a commit that doesn't exist!

You may still have the commit locally, just check it out, tag it and push the tag to the origin.
If you don't have it locally github likely still has it and you can use the api to create a branch
or tag using the commit hash. See https://stackoverflow.com/questions/10098095/git-can-i-view-the-reflog-of-a-remote



If including this fork in a project using go modules, specify the following to use version X.Y.Z
```
replace github.com/lucas-clemente/quic-go => github.com/getlantern/quic-go vX.Y.Z
```

This fork allows certain customizations and exposes some internal details that
are necessary for lantern/oquic development but may not be fully in spec
with QUIC or are not currently justifiable/understood needs upstream.

These include things like:
* making it possible to exclude SNI information
* exposing internal bandwidth estimates from congestion control algorithms
* making the quic packet size externally customizable

# A QUIC implementation in pure Go

<img src="docs/quic.png" width=303 height=124>
Expand Down
12 changes: 7 additions & 5 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,11 @@ func newClient(
) (*client, error) {
if tlsConf == nil {
tlsConf = &tls.Config{}
} else {
tlsConf = tlsConf.Clone()
}
if tlsConf.ServerName == "" {
// ServerName is only defaulted to the hostname given
// if there is no tls.Config given. If a tls.Config
// is given with a blank ServerName, no ServerName is
// used. This is similar to standard tls package
// usage.
sni := host
if strings.IndexByte(sni, ':') != -1 {
var err error
Expand All @@ -240,8 +241,9 @@ func newClient(
return nil, err
}
}

tlsConf.ServerName = sni
} else {
tlsConf = tlsConf.Clone()
}

// check that all versions are actually supported
Expand Down
1 change: 1 addition & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ var _ = Describe("Client", func() {
return conn
}
tracer.EXPECT().StartedConnection(packetConn.LocalAddr(), addr, gomock.Any(), gomock.Any())
tlsConf.ServerName = "test.com"
_, err := Dial(
packetConn,
addr,
Expand Down
1 change: 1 addition & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,6 @@ func populateConfig(config *Config, defaultConnIDLen int) *Config {
DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
DisableVersionNegotiationPackets: config.DisableVersionNegotiationPackets,
Tracer: config.Tracer,
UseBBR: config.UseBBR,
}
}
2 changes: 2 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ var _ = Describe("Config", func() {
f.Set(reflect.ValueOf(true))
case "Tracer":
f.Set(reflect.ValueOf(mocklogging.NewMockTracer(mockCtrl)))
case "UseBBR":
f.Set(reflect.ValueOf(false))
default:
Fail(fmt.Sprintf("all fields must be accounted for, but saw unknown field %q", fn))
}
Expand Down
6 changes: 6 additions & 0 deletions connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ var newConnection = func(
s.tracer,
s.logger,
s.version,
conf.UseBBR,
)
initialStream := newCryptoStream()
handshakeStream := newCryptoStream()
Expand Down Expand Up @@ -426,6 +427,7 @@ var newClientConnection = func(
s.tracer,
s.logger,
s.version,
conf.UseBBR,
)
initialStream := newCryptoStream()
handshakeStream := newCryptoStream()
Expand Down Expand Up @@ -2022,3 +2024,7 @@ func (s *connection) NextConnection() Connection {
s.streamsMap.UseResetMaps()
return s
}

func (s *connection) BandwidthEstimate() Bandwidth {
return s.sentPacketHandler.GetBandwidthEstimate()
}
4 changes: 3 additions & 1 deletion integrationtests/self/handshake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,13 @@ var _ = Describe("Handshake tests", func() {
runServer(getTLSConfig())
conn, err := net.ListenUDP("udp", nil)
Expect(err).ToNot(HaveOccurred())
cfg := getTLSClientConfig()
cfg.ServerName = "foo.bar"
_, err = quic.Dial(
conn,
server.Addr(),
"foo.bar",
getTLSClientConfig(),
cfg,
clientConfig,
)
Expect(err).To(HaveOccurred())
Expand Down
3 changes: 2 additions & 1 deletion integrationtests/self/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ var _ = Describe("HTTP tests", func() {
client = &http.Client{
Transport: &http3.RoundTripper{
TLSClientConfig: &tls.Config{
RootCAs: testdata.GetRootCA(),
RootCAs: testdata.GetRootCA(),
ServerName: "localhost",
},
DisableCompression: true,
QuicConfig: getQuicConfig(&quic.Config{
Expand Down
1 change: 1 addition & 0 deletions integrationtests/self/self_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ var _ = BeforeSuite(func() {
root.AddCert(ca)
tlsClientConfig = &tls.Config{
RootCAs: root,
ServerName: "localhost",
NextProtos: []string{alpn},
}

Expand Down
9 changes: 9 additions & 0 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net"
"time"

"github.com/lucas-clemente/quic-go/internal/congestion"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/logging"
Expand All @@ -26,6 +27,9 @@ const (
Version2 = protocol.Version2
)

// Bandwidth (bps)
type Bandwidth = congestion.Bandwidth

// A ClientToken is a token received by the client.
// It can be used to skip address validation on future connection attempts.
type ClientToken struct {
Expand Down Expand Up @@ -184,6 +188,9 @@ type Connection interface {
SendMessage([]byte) error
// ReceiveMessage gets a message received in a datagram, as specified in RFC 9221.
ReceiveMessage() ([]byte, error)

// BandwidthEstimate gets the current estimate of bandwidth in bps
BandwidthEstimate() Bandwidth
}

// An EarlyConnection is a connection that is handshaking.
Expand Down Expand Up @@ -315,6 +322,8 @@ type Config struct {
// Datagrams will only be available when both peers enable datagram support.
EnableDatagrams bool
Tracer logging.Tracer
// UseBBR switches between CUBIC (false) and BBR (true) being used as a congestion control algro
UseBBR bool
}

// ConnectionState records basic details about a QUIC connection
Expand Down
3 changes: 2 additions & 1 deletion internal/ackhandler/ackhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ func NewAckHandler(
tracer logging.ConnectionTracer,
logger utils.Logger,
version protocol.VersionNumber,
useBBR bool,
) (SentPacketHandler, ReceivedPacketHandler) {
sph := newSentPacketHandler(initialPacketNumber, initialMaxDatagramSize, rttStats, clientAddressValidated, pers, tracer, logger)
sph := newSentPacketHandler(initialPacketNumber, initialMaxDatagramSize, rttStats, clientAddressValidated, pers, tracer, logger, useBBR)
return sph, newReceivedPacketHandler(sph, rttStats, logger, version)
}
4 changes: 4 additions & 0 deletions internal/ackhandler/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ackhandler
import (
"time"

"github.com/lucas-clemente/quic-go/internal/congestion"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"
)
Expand Down Expand Up @@ -54,6 +55,9 @@ type SentPacketHandler interface {

GetLossDetectionTimeout() time.Time
OnLossDetectionTimeout() error

// GetBandwidthEstimate gets the current estimate of bandwidth in bps
GetBandwidthEstimate() congestion.Bandwidth
}

type sentPacketTracker interface {
Expand Down
44 changes: 33 additions & 11 deletions internal/ackhandler/sent_packet_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ackhandler
import (
"errors"
"fmt"
"sync/atomic"
"time"

"github.com/lucas-clemente/quic-go/internal/congestion"
Expand Down Expand Up @@ -52,9 +53,10 @@ func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool, rttStat
}

type sentPacketHandler struct {
initialPackets *packetNumberSpace
handshakePackets *packetNumberSpace
appDataPackets *packetNumberSpace
bandwidthEstimate uint64
initialPackets *packetNumberSpace
handshakePackets *packetNumberSpace
appDataPackets *packetNumberSpace

// Do we know that the peer completed address validation yet?
// Always true for the server.
Expand Down Expand Up @@ -111,14 +113,24 @@ func newSentPacketHandler(
pers protocol.Perspective,
tracer logging.ConnectionTracer,
logger utils.Logger,
useBBR bool,
) *sentPacketHandler {
congestion := congestion.NewCubicSender(
congestion.DefaultClock{},
rttStats,
initialMaxDatagramSize,
true, // use Reno
tracer,
)
var congestionControl congestion.SendAlgorithmWithDebugInfos

if useBBR {
congestionControl = congestion.NewBBRSender(
rttStats,
initialMaxDatagramSize,
)
} else {
congestionControl = congestion.NewCubicSender(
congestion.DefaultClock{},
rttStats,
initialMaxDatagramSize,
true, // use Reno
tracer,
)
}

return &sentPacketHandler{
peerCompletedAddressValidation: pers == protocol.PerspectiveServer,
Expand All @@ -127,7 +139,7 @@ func newSentPacketHandler(
handshakePackets: newPacketNumberSpace(0, false, rttStats),
appDataPackets: newPacketNumberSpace(0, true, rttStats),
rttStats: rttStats,
congestion: congestion,
congestion: congestionControl,
perspective: pers,
tracer: tracer,
logger: logger,
Expand Down Expand Up @@ -281,6 +293,7 @@ func (h *sentPacketHandler) sentPacketImpl(packet *Packet) bool /* is ack-elicit
}

func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) (bool /* contained 1-RTT packet */, error) {
defer h.updateBandwidthEstimate()
pnSpace := h.getPacketNumberSpace(encLevel)

largestAcked := ack.LargestAcked()
Expand Down Expand Up @@ -554,6 +567,7 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
}

func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.EncryptionLevel) error {
defer h.updateBandwidthEstimate()
pnSpace := h.getPacketNumberSpace(encLevel)
pnSpace.lossTime = time.Time{}

Expand Down Expand Up @@ -839,3 +853,11 @@ func (h *sentPacketHandler) SetHandshakeConfirmed() {
// Make sure the timer is armed now, if necessary.
h.setLossDetectionTimer()
}

func (h *sentPacketHandler) updateBandwidthEstimate() {
atomic.StoreUint64(&h.bandwidthEstimate, uint64(h.congestion.BandwidthEstimate()))
}

func (h *sentPacketHandler) GetBandwidthEstimate() congestion.Bandwidth {
return congestion.Bandwidth(atomic.LoadUint64(&h.bandwidthEstimate))
}
Loading