From ca362c388b220ffb006bd66db18be122f6440f56 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Nov 2025 11:32:03 +0000 Subject: [PATCH 1/4] Initial plan From 547c8727e09d058bbcc442e77b69c32a1225a11e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Nov 2025 11:37:36 +0000 Subject: [PATCH 2/4] Replace string matching with syscall error type checking for connection resets Co-authored-by: gerhardgruber <1944892+gerhardgruber@users.noreply.github.com> --- .gitignore | 1 + lpr_status.go | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index a1338d6..48231bb 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 .glide/ +*[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f] diff --git a/lpr_status.go b/lpr_status.go index d8f9a27..ba793b6 100644 --- a/lpr_status.go +++ b/lpr_status.go @@ -5,7 +5,7 @@ import ( "fmt" "io" "net" - "strings" + "syscall" "time" ) @@ -99,7 +99,10 @@ func GetStatus(hostname string, port uint16, queue string, long bool, timeout ti opErr := &net.OpError{} if errors.As(err, &opErr) { - if strings.Contains(opErr.Error(), "connection was forcibly closed by the remote host") || strings.Contains(opErr.Error(), "connection reset by peer") { + // Check for connection reset errors at the syscall level + // This works cross-platform: ECONNRESET on Unix-like systems, + // WSAECONNRESET on Windows + if errors.Is(opErr, syscall.ECONNRESET) { logDebugf("Ignoring forceful connection closure by server") break } From 67aca208c4bc61ff39017b277f9f2a0a6bcd8999 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Nov 2025 11:38:48 +0000 Subject: [PATCH 3/4] Fix error checking to use opErr.Err instead of opErr Co-authored-by: gerhardgruber <1944892+gerhardgruber@users.noreply.github.com> --- lpr_status.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lpr_status.go b/lpr_status.go index ba793b6..bd92711 100644 --- a/lpr_status.go +++ b/lpr_status.go @@ -102,7 +102,7 @@ func GetStatus(hostname string, port uint16, queue string, long bool, timeout ti // Check for connection reset errors at the syscall level // This works cross-platform: ECONNRESET on Unix-like systems, // WSAECONNRESET on Windows - if errors.Is(opErr, syscall.ECONNRESET) { + if errors.Is(opErr.Err, syscall.ECONNRESET) { logDebugf("Ignoring forceful connection closure by server") break } From be2e308624be1e82c0c4d2c8194ce94c8b7bfe13 Mon Sep 17 00:00:00 2001 From: Gerhard Gruber Date: Tue, 25 Nov 2025 16:30:46 +0100 Subject: [PATCH 4/4] small improvements --- .gitignore | 1 - lpr_daemon.go | 26 ++++++++++++++------------ lpr_daemon_test.go | 13 ++++++++----- lpr_status.go | 3 +-- lpr_status_other.go | 14 ++++++++++++++ lpr_status_windows.go | 11 +++++++++++ 6 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 lpr_status_other.go create mode 100644 lpr_status_windows.go diff --git a/.gitignore b/.gitignore index 48231bb..a1338d6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,3 @@ # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 .glide/ -*[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f] diff --git a/lpr_daemon.go b/lpr_daemon.go index d0edc5a..7aabb89 100644 --- a/lpr_daemon.go +++ b/lpr_daemon.go @@ -1,7 +1,6 @@ package lprlib import ( - "context" "errors" "fmt" "io" @@ -33,10 +32,6 @@ type QueueState func(queue string, list string, long bool) string type ExternalIDCallbackFunc func() uint64 -func init() { - rand.Seed(time.Now().UnixMicro()) -} - // LprDaemon structure type LprDaemon struct { finishedConns chan *LprConnection @@ -287,10 +282,6 @@ type LprConnection struct { // SaveName The File name of the new file SaveName string - // ctx is the lpr daemon's context. - // The connection must be closed once the context is canceled. - ctx context.Context - // daemon contains a reference to the LprDaemon daemon *LprDaemon @@ -376,16 +367,27 @@ func (lpr *LprConnection) RunConnection() { } defer traceFile.Close() logDebugf("Created trace file %s", traceFile.Name()) - traceFile.WriteString(fmt.Sprintf("LPR connection trace %s\n", time.Now())) + + _, err = fmt.Fprintf(traceFile, "LPR connection trace %s\n", time.Now()) + if err != nil { + logErrorf("failed to write to trace file %s: %v", traceFile.Name(), err) + } } for lpr.Status != Error && lpr.Status != End { command, err := lpr.ReadCommand() if traceFile != nil { - traceFile.WriteString(fmt.Sprintf("received message %d:\n", len(command))) + _, traceErr := fmt.Fprintf(traceFile, "received message %d:\n", len(command)) + if traceErr != nil { + logErrorf("failed to write to trace file %s: %v", traceFile.Name(), traceErr) + } + if err != nil { - traceFile.WriteString(fmt.Sprintf("error: %v\n", err)) + _, traceErr = fmt.Fprintf(traceFile, "error: %v\n", err) + if traceErr != nil { + logErrorf("failed to write to trace file %s: %v", traceFile.Name(), traceErr) + } } else { traceFile.WriteString("-----\n") traceFile.Write(command) diff --git a/lpr_daemon_test.go b/lpr_daemon_test.go index e70b838..01eee5f 100644 --- a/lpr_daemon_test.go +++ b/lpr_daemon_test.go @@ -156,7 +156,7 @@ func TestDaemonLargeFileConnection(t *testing.T) { conn := <-lprd.FinishedConnections() - out, err = ioutil.ReadFile(conn.SaveName) + out, err = os.ReadFile(conn.SaveName) if err != nil { t.Error(err) } else { @@ -243,7 +243,7 @@ func TestDaemonMultipleConnection(t *testing.T) { i := 0 for conn := range lprd.FinishedConnections() { - out, err = ioutil.ReadFile(conn.SaveName) + out, err = os.ReadFile(conn.SaveName) if err != nil { t.Error(err) } else { @@ -288,7 +288,7 @@ func generateTempFile(dir, prefix, text string) (string, error) { var err error var file *os.File - file, err = ioutil.TempFile(dir, prefix) + file, err = os.CreateTemp(dir, prefix) if err != nil { return "", err } @@ -413,6 +413,9 @@ func TestDaemonClose(t *testing.T) { conn := <-lprd.FinishedConnections() require.Equal(t, End, conn.Status) + err = os.Remove(conn.SaveName) + require.Nil(t, err) + // no new connection may be opened lprs = LprSend{} err = lprs.Init("127.0.0.1", name, port, "raw", "TestUser", time.Minute) @@ -457,7 +460,7 @@ func TestDaemonFileSize(t *testing.T) { con := <-lprd.FinishedConnections() require.Equal(t, End, con.Status) - out, err = ioutil.ReadFile(con.SaveName) + out, err = os.ReadFile(con.SaveName) require.Nil(t, err) err = os.Remove(con.SaveName) require.Nil(t, err) @@ -501,7 +504,7 @@ func TestDaemonFileSize(t *testing.T) { con = <-lprd.FinishedConnections() require.Equal(t, End, con.Status) - out, err = ioutil.ReadFile(con.SaveName) + out, err = os.ReadFile(con.SaveName) require.Nil(t, err) err = os.Remove(con.SaveName) require.Nil(t, err) diff --git a/lpr_status.go b/lpr_status.go index bd92711..3a3eeaf 100644 --- a/lpr_status.go +++ b/lpr_status.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "net" - "syscall" "time" ) @@ -102,7 +101,7 @@ func GetStatus(hostname string, port uint16, queue string, long bool, timeout ti // Check for connection reset errors at the syscall level // This works cross-platform: ECONNRESET on Unix-like systems, // WSAECONNRESET on Windows - if errors.Is(opErr.Err, syscall.ECONNRESET) { + if isConnResetErr(opErr) { logDebugf("Ignoring forceful connection closure by server") break } diff --git a/lpr_status_other.go b/lpr_status_other.go new file mode 100644 index 0000000..391a8f9 --- /dev/null +++ b/lpr_status_other.go @@ -0,0 +1,14 @@ +//go:build !windows +// +build !windows + +package lprlib + +import ( + "errors" + "net" + "syscall" +) + +func isConnResetErr(err *net.OpError) bool { + return errors.Is(err.Err, syscall.ECONNRESET) +} diff --git a/lpr_status_windows.go b/lpr_status_windows.go new file mode 100644 index 0000000..40b5b79 --- /dev/null +++ b/lpr_status_windows.go @@ -0,0 +1,11 @@ +package lprlib + +import ( + "errors" + "net" + "syscall" +) + +func isConnResetErr(err *net.OpError) bool { + return errors.Is(err.Err, syscall.ECONNRESET) || errors.Is(err.Err, syscall.WSAECONNRESET) +}