Skip to content

Commit 71d1b5e

Browse files
authoredNov 12, 2023
Merge pull request #92 from pin/shutdown-hook-race-fix
Make Shutdown blocking to ensure outstanding requests completion
2 parents 5fda30d + c06e820 commit 71d1b5e

File tree

3 files changed

+17
-8
lines changed

3 files changed

+17
-8
lines changed
 

‎README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Set of features is sufficient for PXE boot support.
1717
import "github.com/pin/tftp/v3"
1818
```
1919

20-
The package is cohesive to Golang `io`. Particularly it implements
20+
The package is cohesive to Golang `io` and implements
2121
`io.ReaderFrom` and `io.WriterTo` interfaces. That allows efficient data
2222
transmission without unnecessary memory copying and allocations.
2323

@@ -71,6 +71,8 @@ func main() {
7171
}
7272
```
7373

74+
See [gotftpd](https://github.com/pin/golang-tftp-example/blob/master/src/gotftpd/main.go) in [golang-tftp-example](https://github.com/pin/golang-tftp-example) repository for working code.
75+
7476
TFTP Client
7577
-----------
7678
Upload file to server:
@@ -98,7 +100,7 @@ n, err := wt.WriteTo(file)
98100
fmt.Printf("%d bytes received\n", n)
99101
```
100102

101-
Note: please handle errors better :)
103+
See [goftp](https://github.com/pin/golang-tftp-example/blob/master/src/gotftp/main.go) in [golang-tftp-example](https://github.com/pin/golang-tftp-example) repository for working code.
102104

103105
TSize option
104106
------------

‎server.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,8 @@ func (s *Server) ListenAndServe(addr string) error {
194194
// Serve starts server provided already opened UDP connection. It is
195195
// useful for the case when you want to run server in separate goroutine
196196
// but still want to be able to handle any errors opening connection.
197-
// Serve returns when Shutdown is called or connection is closed.
197+
// Serve returns when Shutdown is called.
198198
func (s *Server) Serve(conn net.PacketConn) error {
199-
// defer conn.Close()
200199
laddr := conn.LocalAddr()
201200
host, _, err := net.SplitHostPort(laddr.String())
202201
if err != nil {
@@ -232,7 +231,7 @@ func (s *Server) Serve(conn net.PacketConn) error {
232231
for {
233232
select {
234233
case <-s.cancel.Done():
235-
s.wg.Wait()
234+
// Stop server because Shutdown was called
236235
return nil
237236
default:
238237
var err error
@@ -250,7 +249,6 @@ func (s *Server) Serve(conn net.PacketConn) error {
250249
}
251250
}
252251
}
253-
return nil
254252
}
255253

256254
// Yes, I don't really like having separate IPv4 and IPv6 variants,
@@ -309,13 +307,22 @@ func (s *Server) processRequest() error {
309307

310308
// Shutdown make server stop listening for new requests, allows
311309
// server to finish outstanding transfers and stops server.
310+
// Shutdown blocks until all outstanding requests are processed or timed out.
311+
// Calling Shutdown from the handler or hook might cause deadlock.
312312
func (s *Server) Shutdown() {
313313
if !s.singlePort {
314314
s.Lock()
315-
s.conn.Close()
315+
// Connection could not exist if Serve or
316+
// ListenAndServe was never called.
317+
if s.conn != nil {
318+
s.conn.Close()
319+
}
316320
s.Unlock()
317321
}
318322
s.cancelFn()
323+
if !s.singlePort {
324+
s.wg.Wait()
325+
}
319326
}
320327

321328
func (s *Server) handlePacket(localAddr net.IP, remoteAddr *net.UDPAddr, buffer []byte, n, maxBlockLen int, listener chan []byte) error {

‎tftp_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func TestPackUnpack(t *testing.T) {
6464
v := []string{"test-filename/with-subdir"}
6565
testOptsList := []options{
6666
nil,
67-
options{
67+
{
6868
"tsize": "1234",
6969
"blksize": "22",
7070
},

0 commit comments

Comments
 (0)
Please sign in to comment.