From 6810e50c2c68a05c5d98188d0bba6381cbfc3a7a Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Thu, 4 Jun 2026 23:19:15 +0800 Subject: [PATCH] fix(handler/serial): record-after-write ordering, nil Router guards, consistent ReadTimeout - conn.go: Write() now writes first then records b[:n] (not len(b)), matching the Read() pattern and preventing phantom data on failures. - handler.go: add nil Router check before h.options.Router.Dial() in Handle's non-hop path to return a clear error instead of panicking. - handler.go: guard h.options.Router against nil in forwardSerial; restructure if/else so ReadTimeout is applied in both the direct OpenPort path and when the Router has no chain configured. --- handler/serial/conn.go | 13 ++++++++----- handler/serial/handler.go | 14 +++++++++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/handler/serial/conn.go b/handler/serial/conn.go index 2a58d778..ddc4c45f 100644 --- a/handler/serial/conn.go +++ b/handler/serial/conn.go @@ -40,8 +40,10 @@ func (c *recorderConn) Read(b []byte) (n int, err error) { return } -func (c *recorderConn) Write(b []byte) (int, error) { - if c.recorder.Recorder != nil { +func (c *recorderConn) Write(b []byte) (n int, err error) { + n, err = c.Conn.Write(b) + + if n > 0 && c.recorder.Recorder != nil { var buf bytes.Buffer if c.recorder.Options != nil && c.recorder.Options.Direction { buf.WriteByte('<') @@ -53,11 +55,12 @@ func (c *recorderConn) Write(b []byte) (int, error) { buf.WriteByte('\n') } if c.recorder.Options != nil && c.recorder.Options.Hexdump { - buf.WriteString(hex.Dump(b)) + buf.WriteString(hex.Dump(b[:n])) } else { - buf.Write(b) + buf.Write(b[:n]) } c.recorder.Recorder.Record(context.Background(), buf.Bytes()) } - return c.Conn.Write(b) + + return } diff --git a/handler/serial/handler.go b/handler/serial/handler.go index e38d8ece..40cd1e4f 100644 --- a/handler/serial/handler.go +++ b/handler/serial/handler.go @@ -93,6 +93,11 @@ func (h *serialHandler) Handle(ctx context.Context, conn net.Conn, opts ...handl return h.forwardSerial(ctx, conn, target, log) } + if h.options.Router == nil { + err := errors.New("router not available") + log.Error(err) + return err + } cc, err := h.options.Router.Dial(ctx, "tcp", "@") if err != nil { log.Error(err) @@ -118,9 +123,12 @@ func (h *serialHandler) forwardSerial(ctx context.Context, conn net.Conn, target cfg := serial.ParseConfigFromAddr(conn.LocalAddr().String()) cfg.Name = target.Addr - if opts := h.options.Router.Options(); opts != nil && opts.Chain != nil { - port, err = h.options.Router.Dial(ctx, "serial", serial.AddrFromConfig(cfg)) - } else { + if h.options.Router != nil { + if opts := h.options.Router.Options(); opts != nil && opts.Chain != nil { + port, err = h.options.Router.Dial(ctx, "serial", serial.AddrFromConfig(cfg)) + } + } + if port == nil && err == nil { cfg.ReadTimeout = h.md.timeout port, err = serial.OpenPort(cfg) }