@@ -17,6 +17,7 @@ import (
1717 "sync/atomic"
1818 "time"
1919
20+ "github.com/cenkalti/backoff/v4"
2021 "github.com/insomniacslk/dhcp/dhcpv6"
2122)
2223
@@ -52,7 +53,7 @@ type Client struct {
5253 ifaceHWAddr net.HardwareAddr
5354 conn net.PacketConn
5455 timeout time.Duration
55- retry int
56+ retry uint64
5657 logger logger
5758
5859 // bufferCap is the channel capacity for each TransactionID.
@@ -272,7 +273,7 @@ func WithLogDroppedPackets() ClientOpt {
272273// WithRetry configures the number of retransmissions to attempt.
273274//
274275// Default is 3.
275- func WithRetry (r int ) ClientOpt {
276+ func WithRetry (r uint64 ) ClientOpt {
276277 return func (c * Client ) {
277278 c .retry = r
278279 }
@@ -443,7 +444,8 @@ var errDeadlineExceeded = errors.New("INTERNAL ERROR: deadline exceeded")
443444// If match is nil, the first packet matching the Transaction ID is returned.
444445func (c * Client ) SendAndRead (ctx context.Context , dest * net.UDPAddr , msg * dhcpv6.Message , match Matcher ) (* dhcpv6.Message , error ) {
445446 var response * dhcpv6.Message
446- err := c .retryFn (func (timeout time.Duration ) error {
447+ timeout := c .timeout
448+ err := backoff .Retry (func () error {
447449 ch , rem , err := c .send (dest , msg )
448450 if err != nil {
449451 return err
@@ -457,6 +459,7 @@ func (c *Client) SendAndRead(ctx context.Context, dest *net.UDPAddr, msg *dhcpv6
457459 return ErrNoResponse
458460
459461 case <- time .After (timeout ):
462+ timeout *= 2
460463 return errDeadlineExceeded
461464
462465 case <- ctx .Done ():
@@ -470,7 +473,7 @@ func (c *Client) SendAndRead(ctx context.Context, dest *net.UDPAddr, msg *dhcpv6
470473 }
471474 }
472475 }
473- })
476+ }, backoff . WithContext ( backoff . WithMaxRetries ( backoff . NewExponentialBackOff (), c . retry ), ctx ) )
474477 if err == errDeadlineExceeded {
475478 return nil , ErrNoResponse
476479 }
@@ -479,25 +482,3 @@ func (c *Client) SendAndRead(ctx context.Context, dest *net.UDPAddr, msg *dhcpv6
479482 }
480483 return response , nil
481484}
482-
483- func (c * Client ) retryFn (fn func (timeout time.Duration ) error ) error {
484- timeout := c .timeout
485-
486- // Each retry takes the amount of timeout at worst.
487- for i := 0 ; i < c .retry || c .retry < 0 ; i ++ {
488- switch err := fn (timeout ); err {
489- case nil :
490- // Got it!
491- return nil
492-
493- case errDeadlineExceeded :
494- // Double timeout, then retry.
495- timeout *= 2
496-
497- default :
498- return err
499- }
500- }
501-
502- return errDeadlineExceeded
503- }
0 commit comments