Skip to content

Commit c48c89f

Browse files
authored
Merge pull request #27 from acd/pluggable-backoff
Pluggable backoff
2 parents 6617275 + 0f0df0d commit c48c89f

File tree

4 files changed

+46
-7
lines changed

4 files changed

+46
-7
lines changed

README.md

+20-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func readHandler(filename string, rf io.ReaderFrom) error {
4545
}
4646

4747
// writeHandler is called when client starts file upload to server
48-
func writeHanlder(filename string, wt io.WriterTo) error {
48+
func writeHandler(filename string, wt io.WriterTo) error {
4949
file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
5050
if err != nil {
5151
fmt.Fprintf(os.Stderr, "%v\n", err)
@@ -62,7 +62,7 @@ func writeHanlder(filename string, wt io.WriterTo) error {
6262

6363
func main() {
6464
// use nil in place of handler to disable read or write operations
65-
s := tftp.NewServer(readHandler, writeHanlder)
65+
s := tftp.NewServer(readHandler, writeHandler)
6666
s.SetTimeout(5 * time.Second) // optional
6767
err := s.ListenAndServe(":69") // blocks until s.Shutdown() is called
6868
if err != nil {
@@ -149,4 +149,22 @@ func readHandler(filename string, rf io.ReaderFrom) error {
149149
...
150150
// ReadFrom ...
151151

152+
Backoff
153+
-------
154+
155+
The default backoff before retransmitting an unacknowledged packet is a
156+
random duration between 0 and 1 second. This behavior can be overridden
157+
in clients and servers by providing a custom backoff calculation function.
158+
159+
```go
160+
s := tftp.NewServer(readHandler, writeHandler)
161+
s.SetBackoff(func (attempts int) time.Duration {
162+
return time.Duration(attempts) * time.Second
163+
})
164+
```
165+
166+
or, for no backoff
167+
168+
```go
169+
s.SetBackoff(func (int) time.Duration { return 0 })
152170
```

backoff.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ const (
1010
defaultRetries = 5
1111
)
1212

13+
type backoffFunc func(int) time.Duration
14+
1315
type backoff struct {
1416
attempt int
17+
handler backoffFunc
1518
}
1619

1720
func (b *backoff) reset() {
@@ -23,6 +26,10 @@ func (b *backoff) count() int {
2326
}
2427

2528
func (b *backoff) backoff() {
26-
time.Sleep(time.Duration(rand.Int63n(int64(time.Second))))
29+
if b.handler == nil {
30+
time.Sleep(time.Duration(rand.Int63n(int64(time.Second))))
31+
} else {
32+
time.Sleep(b.handler(b.attempt))
33+
}
2734
b.attempt++
2835
}

client.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,17 @@ func (c *Client) SetRetries(count int) {
3939
c.retries = count
4040
}
4141

42+
// SetBackoff sets a user provided function that is called to provide a
43+
// backoff duration prior to retransmitting an unacknowledged packet.
44+
func (c *Client) SetBackoff(h backoffFunc) {
45+
c.backoff = h
46+
}
47+
4248
type Client struct {
4349
addr *net.UDPAddr
4450
timeout time.Duration
4551
retries int
52+
backoff backoffFunc
4653
blksize int
4754
tsize bool
4855
}
@@ -57,7 +64,7 @@ func (c Client) Send(filename string, mode string) (io.ReaderFrom, error) {
5764
send: make([]byte, datagramLength),
5865
receive: make([]byte, datagramLength),
5966
conn: conn,
60-
retry: &backoff{},
67+
retry: &backoff{handler: c.backoff},
6168
timeout: c.timeout,
6269
retries: c.retries,
6370
addr: c.addr,
@@ -90,7 +97,7 @@ func (c Client) Receive(filename string, mode string) (io.WriterTo, error) {
9097
send: make([]byte, datagramLength),
9198
receive: make([]byte, datagramLength),
9299
conn: conn,
93-
retry: &backoff{},
100+
retry: &backoff{handler: c.backoff},
94101
timeout: c.timeout,
95102
retries: c.retries,
96103
addr: c.addr,

server.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ func NewServer(readHandler func(filename string, rf io.ReaderFrom) error,
2525
type Server struct {
2626
readHandler func(filename string, rf io.ReaderFrom) error
2727
writeHandler func(filename string, wt io.WriterTo) error
28+
backoff backoffFunc
2829
conn *net.UDPConn
2930
quit chan chan struct{}
3031
wg sync.WaitGroup
@@ -54,6 +55,12 @@ func (s *Server) SetRetries(count int) {
5455
}
5556
}
5657

58+
// SetBackoff sets a user provided function that is called to provide a
59+
// backoff duration prior to retransmitting an unacknowledged packet.
60+
func (s *Server) SetBackoff(h backoffFunc) {
61+
s.backoff = h
62+
}
63+
5764
// ListenAndServe binds to address provided and start the server.
5865
// ListenAndServe returns when Shutdown is called.
5966
func (s *Server) ListenAndServe(addr string) error {
@@ -129,7 +136,7 @@ func (s *Server) processRequest(conn *net.UDPConn) error {
129136
send: make([]byte, datagramLength),
130137
receive: make([]byte, datagramLength),
131138
conn: conn,
132-
retry: &backoff{},
139+
retry: &backoff{handler: s.backoff},
133140
timeout: s.timeout,
134141
retries: s.retries,
135142
addr: remoteAddr,
@@ -166,7 +173,7 @@ func (s *Server) processRequest(conn *net.UDPConn) error {
166173
receive: make([]byte, datagramLength),
167174
tid: remoteAddr.Port,
168175
conn: conn,
169-
retry: &backoff{},
176+
retry: &backoff{handler: s.backoff},
170177
timeout: s.timeout,
171178
retries: s.retries,
172179
addr: remoteAddr,

0 commit comments

Comments
 (0)