diff --git a/conn.go b/conn.go index 1ce9725f..3bb2ba15 100644 --- a/conn.go +++ b/conn.go @@ -18,7 +18,9 @@ type conn struct { } // the orderID is used in server mode if the allocator is enabled. -// For the client mode just pass 0 +// For the client mode just pass 0. +// It returns io.EOF if the connection is closed and +// there are no more packets to read. func (c *conn) recvPacket(orderID uint32) (uint8, []byte, error) { return recvPacket(c, c.alloc, orderID) } diff --git a/packet.go b/packet.go index b06d0b95..f768741f 100644 --- a/packet.go +++ b/packet.go @@ -290,6 +290,9 @@ func recvPacket(r io.Reader, alloc *allocator, orderID uint32) (uint8, []byte, e b = make([]byte, length) } if _, err := io.ReadFull(r, b[:length]); err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } debug("recv packet %d bytes: err %v", length, err) return 0, nil, err } diff --git a/server.go b/server.go index 503454e6..2e419f59 100644 --- a/server.go +++ b/server.go @@ -327,7 +327,7 @@ func handlePacket(s *Server, p orderedRequest) error { } // Serve serves SFTP connections until the streams stop or the SFTP subsystem -// is stopped. +// is stopped. It returns nil if the server exits cleanly. func (svr *Server) Serve() error { defer func() { if svr.pktMgr.alloc != nil { @@ -353,6 +353,10 @@ func (svr *Server) Serve() error { for { pktType, pktBytes, err = svr.serverConn.recvPacket(svr.pktMgr.getNextOrderID()) if err != nil { + // Check whether the connection terminated cleanly in-between packets. + if err == io.EOF { + err = nil + } // we don't care about releasing allocated pages here, the server will quit and the allocator freed break }