From: Brad Fitzpatrick Date: Sun, 10 Mar 2013 02:14:00 +0000 (-0800) Subject: net: evaluate the timeout dial opt's deadline at dial time X-Git-Tag: go1.1rc2~618 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=8d51c330122a88a7f6644580c6907ca634357f16;p=gostls13.git net: evaluate the timeout dial opt's deadline at dial time Previously it was evaluated once, so re-using the timeout option repeatedly would always generate the same deadine. Also switch to doing just one pass over the options, making the private interface actually useful. R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/7608045 --- diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go index 22e1e7dd8a..2e15c06cc9 100644 --- a/src/pkg/net/dial.go +++ b/src/pkg/net/dial.go @@ -11,7 +11,27 @@ import ( // A DialOption modifies a DialOpt call. type DialOption interface { - dialOption() + setDialOpt(*dialOpts) +} + +var noLocalAddr Addr // nil + +// dialOpts holds all the dial options, populated by a DialOption's +// setDialOpt. +// +// All fields may be their zero value. +type dialOpts struct { + deadline time.Time + localAddr Addr + network string // if empty, "tcp" + deferredConnect bool +} + +func (o *dialOpts) net() string { + if o.network == "" { + return "tcp" + } + return o.network } var ( @@ -38,7 +58,9 @@ func Network(net string) DialOption { type dialNetwork string -func (dialNetwork) dialOption() {} +func (s dialNetwork) setDialOpt(o *dialOpts) { + o.network = string(s) +} // Deadline returns a DialOption to fail a dial that doesn't // complete before t. @@ -46,19 +68,29 @@ func Deadline(t time.Time) DialOption { return dialDeadline(t) } +type dialDeadline time.Time + +func (t dialDeadline) setDialOpt(o *dialOpts) { + o.deadline = time.Time(t) +} + // Timeout returns a DialOption to fail a dial that doesn't // complete within the provided duration. func Timeout(d time.Duration) DialOption { - return dialDeadline(time.Now().Add(d)) + return dialTimeoutOpt(d) } -type dialDeadline time.Time +type dialTimeoutOpt time.Duration -func (dialDeadline) dialOption() {} +func (d dialTimeoutOpt) setDialOpt(o *dialOpts) { + o.deadline = time.Now().Add(time.Duration(d)) +} type tcpFastOpen struct{} -func (tcpFastOpen) dialOption() {} +func (tcpFastOpen) setDialOpt(o *dialOpts) { + o.deferredConnect = true +} // TODO(bradfitz): implement this (golang.org/issue/4842) and unexport this. // @@ -74,7 +106,9 @@ type localAddrOption struct { la Addr } -func (localAddrOption) dialOption() {} +func (a localAddrOption) setDialOpt(o *dialOpts) { + o.localAddr = a.la +} // LocalAddress returns a dial option to perform a dial with the // provided local address. The address must be of a compatible type @@ -155,47 +189,19 @@ func Dial(net, addr string) (Conn, error) { return DialOpt(addr, dialNetwork(net)) } -func netFromOptions(opts []DialOption) string { - for _, opt := range opts { - if p, ok := opt.(dialNetwork); ok { - return string(p) - } - } - return "tcp" -} - -func deadlineFromOptions(opts []DialOption) time.Time { - for _, opt := range opts { - if d, ok := opt.(dialDeadline); ok { - return time.Time(d) - } - } - return noDeadline -} - -var noLocalAddr Addr // nil - -func localAddrFromOptions(opts []DialOption) Addr { - for _, opt := range opts { - if o, ok := opt.(localAddrOption); ok { - return o.la - } - } - return noLocalAddr -} - // DialOpt dials addr using the provided options. // If no options are provided, DialOpt(addr) is equivalent // to Dial("tcp", addr). See Dial for the syntax of addr. func DialOpt(addr string, opts ...DialOption) (Conn, error) { - net := netFromOptions(opts) - deadline := deadlineFromOptions(opts) - la := localAddrFromOptions(opts) - ra, err := resolveAddr("dial", net, addr, deadline) + var o dialOpts + for _, opt := range opts { + opt.setDialOpt(&o) + } + ra, err := resolveAddr("dial", o.net(), addr, o.deadline) if err != nil { return nil, err } - return dial(net, addr, la, ra, deadline) + return dial(o.net(), addr, o.localAddr, ra, o.deadline) } func dial(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {