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

Support context.Context based cancellation #191

Merged
merged 3 commits into from
Feb 15, 2020
Merged

Conversation

at-wat
Copy link
Member

@at-wat at-wat commented Feb 11, 2020

DialWithContext(), ClientWithContext() and ServerWithContext()
are added. Instead, ConnectTimeout is dropped from Config.

Reference issue

Closes #189

DialWithContext(), ClientWithContext() and ServerWithContext()
are added. Instead, ConnectTimeout is dropped from Config.
@codecov-io
Copy link

codecov-io commented Feb 11, 2020

Codecov Report

Merging #191 into master will decrease coverage by 0.12%.
The diff coverage is 84.61%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #191      +/-   ##
==========================================
- Coverage   75.36%   75.23%   -0.13%     
==========================================
  Files          63       63              
  Lines        3540     3550      +10     
==========================================
+ Hits         2668     2671       +3     
- Misses        586      591       +5     
- Partials      286      288       +2
Flag Coverage Δ
#go 75.23% <84.61%> (-0.02%) ⬇️
#wasm 69.57% <76.92%> (-0.23%) ⬇️
Impacted Files Coverage Δ
listener.go 57.89% <ø> (ø) ⬆️
resume.go 62.5% <100%> (ø) ⬆️
config.go 96% <83.33%> (-4%) ⬇️
conn.go 80.78% <84.21%> (-1.08%) ⬇️
internal/net/dpipe/dpipe.go 94.11% <0%> (-2.36%) ⬇️
client_handlers.go 78.16% <0%> (-0.54%) ⬇️
cipher_suite.go 93.04% <0%> (+3.47%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 34883a7...821a2c5. Read the comment docs.

ConnectTimeout *time.Duration
// function to make a context used in Dial(), Client(), Server(), and Accept().
// If nil, DefaultConnectContextMaker is used.
ConnectContextMaker func() (context.Context, func())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function type suggest user to use cancelable contexts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine removing this entirely! ping @daenney make sure I am not making a bad decision :)

  • Context with a deadline if they still need deadlines.
  • We don't support Dialer, so not like we are breaking any APIs (Dialer also doesn't support server so will not work for us)

Copy link
Member Author

@at-wat at-wat Feb 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this to make it possible to customize the behavior of accepting connection in dtls.listener.

As Listen() blocks until incoming connection and return established dtls.Conn, deadline timer must be initialized at the time the first packet, that triggers dtls handshake, arrives.

Adding this makes it easy to implement both handshake timeout and graceful shutdown of server like:

func DTLSServer(ctx context.Context) {
	l, err := dtls.Listen(..., &dtls.Config{
		return context.WithTimeout(ctx, 10*time.Second)
	})
	for {
		conn, err := l.Accept()
		...
	}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the ping. I think this makes sense, and the fact that when not explicitly provided we inject a default context with a proper timeout makes me happy.

errors.go Outdated Show resolved Hide resolved
@at-wat at-wat force-pushed the context-based-cancel branch 2 times, most recently from d1fb931 to 821a2c5 Compare February 12, 2020 08:09
@at-wat at-wat changed the title [Discussion needed] Support context.Context based cancellation Support context.Context based cancellation Feb 12, 2020
@at-wat at-wat marked this pull request as ready for review February 12, 2020 12:13
@at-wat
Copy link
Member Author

at-wat commented Feb 12, 2020

@daenney @Sean-Der @jkralik please take a look when you have time!

@at-wat
Copy link
Member Author

at-wat commented Feb 14, 2020

Increased context related test coverage.

@at-wat at-wat force-pushed the context-based-cancel branch 2 times, most recently from 088d2d2 to ff4ef4b Compare February 14, 2020 17:22
config.go Outdated

// MTU is the length at which handshake messages will be fragmented to
// fit within the maximum transmission unit (default is 1200 bytes)
MTU int
}

const defaultConnectTimeout = 30 * time.Second
// DefaultConnectContextMaker is a default ConnectContextMaker used in Dial(), Client(), Server(), and Accept().
var DefaultConnectContextMaker = func() (context.Context, func()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind making this a function? I don't believe modification is anything we will ever need!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In stdlib, default things are often defined as global variable, e.g. net.DefaultResolver: https://golang.org/pkg/net/#pkg-variables

One of my intention of this was providing an example of ConnectContextMaker implementation on godoc.
I'll make it a function, unexpose, and explicitly add an example as a comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I am wrong! Wasn't aware this was a Go pattern. I just always avoid globals and the possibility of people modifying things.

If you want to revert and go back to the way you had it I am happy with that :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But yea, it may allow something bad. If one of the library does

func init() {
    net.DefaultResolver = &net.Resolver{
        Dial: EvilDial,
    }
}

It's weird.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I agree this is a pattern in stdlib, but I think this is a place where we should deviate from stdlib, and I'm happy to see the defaultConnectContextMaker instead.

I understand why it's historically shown up in stdlib, net/http does something similar with DefaultHTTPClient so you can call a naked http.$Method without needing to create your own http.Client first, but it's proven to be quite the footgun.

@Sean-Der
Copy link
Member

With the next context API is it possible to be notified of a Close now without doing a Read? This is something WebRTC needs. I have a case where there is no SCTP traffic, so the DTLS alert is the fastest way to kill the connection. I was hoping I could do.

ctx, _ := context.WithCancel(context.Background())
c, err := dtls.Client(...)
if err != nil {
  return err
}

go func() {
   <-ctx.Done()
   if ctx.Err() != nil {
     fmt.Println("DTLS Session has ended in error!")
   }
}()


Copy link
Member

@Sean-Der Sean-Der left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@at-wat sorry for being so slow, left some questions! I am happy with this landing in master, we can always iterate/continue to work on it :)

If nil, context.WithTimeout(context.Background(), 30*time.Second)
will be used.
Add Go 1.13 error wrapping compatible error wrapper and
make errConnectTimeout derived from context.DeadlineExceeded.
@at-wat
Copy link
Member Author

at-wat commented Feb 14, 2020

@Sean-Der unfortunately, #191 (comment) is not possible.
context.Context interface doesn't provide a way to cancel itself.
ctx, _ := context.WithCancel(context.Background()) is never been cancelled and just causes context leak.

I think it's better to add a state callback for this purpose.

@Sean-Der
Copy link
Member

@at-wat I am happy with merging! We can always improve things as we go, such a shame about the leakage :(

I will add the state callback soon, need it for good WebRTC behavior

@at-wat at-wat merged commit 34ebfdb into master Feb 15, 2020
@at-wat at-wat deleted the context-based-cancel branch February 15, 2020 13:19
@at-wat
Copy link
Member Author

at-wat commented Feb 15, 2020

Thank you for reviewing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

context.Context based cancellation
4 participants