Skip to content

Commit

Permalink
added multipath to quic
Browse files Browse the repository at this point in the history
This commit introduces Multipath QUIC, a extension to the QUIC protocol
enabling hosts to spread data over multiple paths for a single
connection.
  • Loading branch information
qdeconinck committed Dec 8, 2017
1 parent f4113b7 commit 8073819
Show file tree
Hide file tree
Showing 286 changed files with 20,057 additions and 9,921 deletions.
25 changes: 12 additions & 13 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
sudo: required
dist: trusty

addons:
hosts:
- quic.clemente.io

language: go

services:
- docker

go:
- 1.6.4
- 1.7.5
- 1.8
- 1.9

# first part of the GOARCH workaround
# setting the GOARCH directly doesn't work, since the value will be overwritten later
# so set it to a temporary environment variable first
env:
- TRAVIS_GOARCH=amd64 TESTMODE=unit
- TRAVIS_GOARCH=amd64 TESTMODE=integration
- TRAVIS_GOARCH=386 TESTMODE=unit
- TRAVIS_GOARCH=386 TESTMODE=integration
global:
- TIMESCALE_FACTOR=20
matrix:
- TRAVIS_GOARCH=amd64 TESTMODE=unit
- TRAVIS_GOARCH=amd64 TESTMODE=integration
- TRAVIS_GOARCH=386 TESTMODE=unit
- TRAVIS_GOARCH=386 TESTMODE=integration

# second part of the GOARCH workaround
# now actually set the GOARCH env variable to the value of the temporary variable set earlier
Expand All @@ -31,10 +29,11 @@ before_install:
- go get github.com/onsi/gomega
- export GOARCH=$TRAVIS_GOARCH
- go env # for debugging
- "export DISPLAY=:99.0"
- "Xvfb $DISPLAY &> /dev/null &"

script:
# Retry building up to 3 times as documented here: https://docs.travis-ci.com/user/common-build-problems/#travis_retry
- travis_retry .travis/script.sh
- .travis/script.sh

after_success:
- .travis/after_success.sh
5 changes: 2 additions & 3 deletions .travis/after_success.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#!/usr/bin/env bash

set -e
set -ex

if [ ${TESTMODE} == "unit" ]; then
cat quic-go.coverprofile > coverage.txt
cat */*.coverprofile >> coverage.txt
cat `find . -name "*.coverprofile"` > coverage.txt
bash <(curl -s https://codecov.io/bash) -f coverage.txt
fi
15 changes: 11 additions & 4 deletions .travis/script.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
#!/usr/bin/env bash

set -e
set -ex

go get -t ./...
if [ ${TESTMODE} == "unit" ]; then
ginkgo -r --cover --randomizeAllSpecs --randomizeSuites --trace --progress --skipPackage integrationtests --skipMeasurements
ginkgo -r -v -cover -randomizeAllSpecs -randomizeSuites -trace -skipPackage integrationtests,benchmark
fi

if [ ${TESTMODE} == "integration" ]; then
ginkgo --randomizeAllSpecs --randomizeSuites --trace --progress -focus "Benchmark"
ginkgo -r --randomizeAllSpecs --randomizeSuites --trace --progress integrationtests
# run benchmark tests
ginkgo -randomizeAllSpecs -randomizeSuites -trace benchmark -- -samples=1
# run benchmark tests with the Go race detector
# The Go race detector only works on amd64.
if [ ${TRAVIS_GOARCH} == 'amd64' ]; then
ginkgo -race -randomizeAllSpecs -randomizeSuites -trace benchmark -- -samples=1 -size=10
fi
# run integration tests
ginkgo -r -v -randomizeAllSpecs -randomizeSuites -trace integrationtests
fi
20 changes: 20 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

## v0.6.0 (unreleased)

- Add support for QUIC 38 and 39, drop support for QUIC 35 and 36
- Added `quic.Config` options for maximal flow control windows
- Add a `quic.Config` option for QUIC versions
- Add a `quic.Config` option to request truncation of the connection ID from a server
- Add a `quic.Config` option to configure the source address validation
- Add a `quic.Config` option to configure the handshake timeout
- Add a `quic.Config` option to configure the idle timeout
- Add a `quic.Config` option to configure keep-alive
- Rename the STK to Cookie
- Implement `net.Conn`-style deadlines for streams
- Remove the `tls.Config` from the `quic.Config`. The `tls.Config` must now be passed to the `Dial` and `Listen` functions as a separate parameter. See the [Godoc](https://godoc.org/github.com/lucas-clemente/quic-go) for details.
- Changed the log level environment variable to only accept strings ("DEBUG", "INFO", "ERROR"), see [the wiki](https://github.com/lucas-clemente/quic-go/wiki/Logging) for more details.
- Rename the `h2quic.QuicRoundTripper` to `h2quic.RoundTripper`
- Changed `h2quic.Server.Serve()` to accept a `net.PacketConn`
- Drop support for Go 1.7 and 1.8.
- Various bugfixes
28 changes: 13 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,13 @@ quic-go is an implementation of the [QUIC](https://en.wikipedia.org/wiki/QUIC) p
quic-go is compatible with the current version(s) of Google Chrome and QUIC as deployed on Google's servers. We're actively tracking the development of the Chrome code to ensure compatibility as the protocol evolves. In that process, we're dropping support for old QUIC versions.
As Google's QUIC versions are expected to converge towards the [IETF QUIC draft](https://github.com/quicwg/base-drafts), quic-go will eventually implement that draft.


Major TODOs:

- Better packet loss detection
- Connection migration
- Client-side 0-RTT support
- BBR congestion control

## Guides

Installing deps:
We currently support Go 1.9+.

go get -t
Installing and updating dependencies:

go get -t -u ./...

Running tests:

Expand All @@ -44,9 +38,13 @@ Using Chrome:

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --user-data-dir=/tmp/chrome --no-proxy-server --enable-quic --origin-to-force-quic-on=quic.clemente.io:443 --host-resolver-rules='MAP quic.clemente.io:443 127.0.0.1:6121' https://quic.clemente.io

### QUIC without HTTP/2

Take a look at [this echo example](example/echo/echo.go).

### Using the example client

go run example/client/main.go https://quic.clemente.io
go run example/client/main.go https://clemente.io

## Usage

Expand All @@ -61,14 +59,14 @@ h2quic.ListenAndServeQUIC("localhost:4242", "/path/to/cert/chain.pem", "/path/to

### As a client

See the [example client](example/client/main.go). Use a `QuicRoundTripper` as a `Transport` in a `http.Client`.
See the [example client](example/client/main.go). Use a `h2quic.RoundTripper` as a `Transport` in a `http.Client`.

```go
http.Client{
Transport: &h2quic.QuicRoundTripper{},
Transport: &h2quic.RoundTripper{},
}
```

## Building on Windows
## Contributing

Due to the low Windows timer resolution (see [StackOverflow question](http://stackoverflow.com/questions/37706834/high-resolution-timers-millisecond-precision-in-go-on-windows)) available with Go 1.6.x, some optimizations might not work when compiled with this version of the compiler. Please use Go 1.7 on Windows.
We are always happy to welcome new contributors! We have a number of self-contained issues that are suitable for first-time contributors, they are tagged with [want-help](https://github.com/lucas-clemente/quic-go/issues?q=is%3Aopen+is%3Aissue+label%3Awant-help). If you have any questions, please feel free to reach out by opening an issue or leaving a comment.
2 changes: 1 addition & 1 deletion ackhandler/ackhandler_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import (

func TestCrypto(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "AckHandler (New) Suite")
RunSpecs(t, "AckHandler Suite")
}
34 changes: 22 additions & 12 deletions ackhandler/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,43 @@ package ackhandler
import (
"time"

"github.com/lucas-clemente/quic-go/frames"
"github.com/lucas-clemente/quic-go/protocol"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"
)

// SentPacketHandler handles ACKs received for outgoing packets
type SentPacketHandler interface {
// SentPacket may modify the packet
SentPacket(packet *Packet) error
ReceivedAck(ackFrame *frames.AckFrame, withPacketNumber protocol.PacketNumber, recvTime time.Time) error
ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, recvTime time.Time) error

GetStopWaitingFrame(force bool) *frames.StopWaitingFrame
// Specific to multipath operation
ReceivedClosePath(f *wire.ClosePathFrame, withPacketNumber protocol.PacketNumber, recvTime time.Time) error
SetInflightAsLost()

MaybeQueueRTOs()
SendingAllowed() bool
GetStopWaitingFrame(force bool) *wire.StopWaitingFrame
ShouldSendRetransmittablePacket() bool
DequeuePacketForRetransmission() (packet *Packet)

BytesInFlight() protocol.ByteCount
GetLeastUnacked() protocol.PacketNumber

SendingAllowed() bool
CheckForError() error
GetAlarmTimeout() time.Time
OnAlarm()

TimeOfFirstRTO() time.Time
DuplicatePacket(packet *Packet)

GetStatistics() (uint64, uint64, uint64)
}

// ReceivedPacketHandler handles ACKs needed to send for incoming packets
type ReceivedPacketHandler interface {
ReceivedPacket(packetNumber protocol.PacketNumber, shouldInstigateAck bool) error
ReceivedStopWaiting(*frames.StopWaitingFrame) error
SetLowerLimit(protocol.PacketNumber)

GetAlarmTimeout() time.Time
GetAckFrame() *wire.AckFrame

GetClosePathFrame() *wire.ClosePathFrame

GetAckFrame() *frames.AckFrame
GetStatistics() uint64
}
40 changes: 31 additions & 9 deletions ackhandler/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,56 @@ package ackhandler
import (
"time"

"github.com/lucas-clemente/quic-go/frames"
"github.com/lucas-clemente/quic-go/protocol"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"
)

// A Packet is a packet
// +gen linkedlist
type Packet struct {
PacketNumber protocol.PacketNumber
Frames []frames.Frame
Frames []wire.Frame
Length protocol.ByteCount
EncryptionLevel protocol.EncryptionLevel

MissingReports uint8

SendTime time.Time
}

// GetFramesForRetransmission gets all the frames for retransmission
func (p *Packet) GetFramesForRetransmission() []frames.Frame {
var fs []frames.Frame
func (p *Packet) GetFramesForRetransmission() []wire.Frame {
var fs []wire.Frame
for _, frame := range p.Frames {
switch frame.(type) {
case *frames.AckFrame:
case *wire.AckFrame:
continue
case *frames.StopWaitingFrame:
case *wire.StopWaitingFrame:
continue
}
fs = append(fs, frame)
}
return fs
}

func (p *Packet) IsRetransmittable() bool {
for _, f := range p.Frames {
switch f.(type) {
case *wire.StreamFrame:
return true
case *wire.RstStreamFrame:
return true
case *wire.WindowUpdateFrame:
return true
case *wire.BlockedFrame:
return true
case *wire.PingFrame:
return true
case *wire.GoawayFrame:
return true
case *wire.AddAddressFrame:
return true
case *wire.PathsFrame:
return true
}
}
return false
}
16 changes: 8 additions & 8 deletions ackhandler/packet_test.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
package ackhandler

import (
"github.com/lucas-clemente/quic-go/frames"
"github.com/lucas-clemente/quic-go/internal/wire"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Packet", func() {
Context("getting frames for retransmission", func() {
ackFrame := &frames.AckFrame{LargestAcked: 13}
stopWaitingFrame := &frames.StopWaitingFrame{LeastUnacked: 7331}
windowUpdateFrame := &frames.WindowUpdateFrame{StreamID: 999}
ackFrame := &wire.AckFrame{LargestAcked: 13}
stopWaitingFrame := &wire.StopWaitingFrame{LeastUnacked: 7331}
windowUpdateFrame := &wire.WindowUpdateFrame{StreamID: 999}

streamFrame := &frames.StreamFrame{
streamFrame := &wire.StreamFrame{
StreamID: 5,
Data: []byte{0x13, 0x37},
}

rstStreamFrame := &frames.RstStreamFrame{
rstStreamFrame := &wire.RstStreamFrame{
StreamID: 555,
ErrorCode: 1337,
}

It("returns nil if there are no retransmittable frames", func() {
packet := &Packet{
Frames: []frames.Frame{ackFrame, stopWaitingFrame},
Frames: []wire.Frame{ackFrame, stopWaitingFrame},
}
Expect(packet.GetFramesForRetransmission()).To(BeNil())
})

It("returns all retransmittable frames", func() {
packet := &Packet{
Frames: []frames.Frame{
Frames: []wire.Frame{
windowUpdateFrame,
ackFrame,
stopWaitingFrame,
Expand Down
Loading

0 comments on commit 8073819

Please sign in to comment.