From 44f475c28eeed061f0c31667642f512134eab95a Mon Sep 17 00:00:00 2001 From: Heinz Boehmer Fiehn Date: Wed, 11 Aug 2021 16:11:38 -0700 Subject: [PATCH] nclient6: Use cenkalti/backoff/v4 library to replace backoff algorithm in #296 Signed-off-by: Heinz Boehmer Fiehn --- dhcpv6/nclient6/client.go | 33 +++++++-------------------------- go.mod | 1 + go.sum | 2 ++ 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/dhcpv6/nclient6/client.go b/dhcpv6/nclient6/client.go index 8705a6ab..c8c48bab 100644 --- a/dhcpv6/nclient6/client.go +++ b/dhcpv6/nclient6/client.go @@ -17,6 +17,7 @@ import ( "sync/atomic" "time" + "github.com/cenkalti/backoff/v4" "github.com/insomniacslk/dhcp/dhcpv6" ) @@ -52,7 +53,7 @@ type Client struct { ifaceHWAddr net.HardwareAddr conn net.PacketConn timeout time.Duration - retry int + retry uint64 logger logger // bufferCap is the channel capacity for each TransactionID. @@ -272,7 +273,7 @@ func WithLogDroppedPackets() ClientOpt { // WithRetry configures the number of retransmissions to attempt. // // Default is 3. -func WithRetry(r int) ClientOpt { +func WithRetry(r uint64) ClientOpt { return func(c *Client) { c.retry = r } @@ -443,7 +444,8 @@ var errDeadlineExceeded = errors.New("INTERNAL ERROR: deadline exceeded") // If match is nil, the first packet matching the Transaction ID is returned. func (c *Client) SendAndRead(ctx context.Context, dest *net.UDPAddr, msg *dhcpv6.Message, match Matcher) (*dhcpv6.Message, error) { var response *dhcpv6.Message - err := c.retryFn(func(timeout time.Duration) error { + timeout := c.timeout + err := backoff.Retry(func() error { ch, rem, err := c.send(dest, msg) if err != nil { return err @@ -457,6 +459,7 @@ func (c *Client) SendAndRead(ctx context.Context, dest *net.UDPAddr, msg *dhcpv6 return ErrNoResponse case <-time.After(timeout): + timeout *= 2 return errDeadlineExceeded case <-ctx.Done(): @@ -470,7 +473,7 @@ func (c *Client) SendAndRead(ctx context.Context, dest *net.UDPAddr, msg *dhcpv6 } } } - }) + }, backoff.WithContext(backoff.WithMaxRetries(backoff.NewExponentialBackOff(), c.retry), ctx)) if err == errDeadlineExceeded { return nil, ErrNoResponse } @@ -479,25 +482,3 @@ func (c *Client) SendAndRead(ctx context.Context, dest *net.UDPAddr, msg *dhcpv6 } return response, nil } - -func (c *Client) retryFn(fn func(timeout time.Duration) error) error { - timeout := c.timeout - - // Each retry takes the amount of timeout at worst. - for i := 0; i < c.retry || c.retry < 0; i++ { - switch err := fn(timeout); err { - case nil: - // Got it! - return nil - - case errDeadlineExceeded: - // Double timeout, then retry. - timeout *= 2 - - default: - return err - } - } - - return errDeadlineExceeded -} diff --git a/go.mod b/go.mod index d53b0e47..3295ee95 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/insomniacslk/dhcp go 1.13 require ( + github.com/cenkalti/backoff/v4 v4.1.1 // indirect github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72 github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c diff --git a/go.sum b/go.sum index a89fe9d1..560e7a87 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72 h1:0eU/faU2oDIB2BkQVM02hgRLJjGzzUuRf19HUhp0394=