Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6b39f59
feat: no error return on connection close
Aug 17, 2025
c42b242
feat: no error return on connection close
Aug 17, 2025
829e00e
feat: no error return on connection close
Aug 17, 2025
b255d66
feat: no error return on connection close
Aug 19, 2025
3afdaa0
feat: no error return on connection close
Aug 19, 2025
4de8be1
feat: no error return on connection close
Aug 19, 2025
a43fdd1
feat: no error return on connection close
Aug 31, 2025
762277d
feat: addressed review comments
Sep 20, 2025
b01fcbe
feat: addressed review comments
Oct 20, 2025
3e78cb5
feat: addressed review comments
Oct 20, 2025
29a9bd1
feat:tests are still timing out
Oct 26, 2025
728d9b1
feat: attempt to fix test
Oct 28, 2025
6163d32
feat: addressed review comments
Nov 24, 2025
f6b9134
Merge branch 'main' into feat/no-error-return
jkawan Nov 24, 2025
7c2d72a
feat: resolved merge conflict
Nov 24, 2025
aca6320
feat: test failure fix attempt
Nov 24, 2025
9e80115
Merge branch 'main' into feat/no-error-return
jkawan Nov 25, 2025
c2e7504
feat: test failure fix attempt
Nov 30, 2025
4807820
feat: test failure fix attempt
Nov 30, 2025
197286b
feat: test failure fix attempt
Nov 30, 2025
b37a245
feat: test failure fix attempt
Nov 30, 2025
42f7142
feat: test failure fix attempt
Nov 30, 2025
fdaceaf
feat: test failure fix attempt
Nov 30, 2025
990cca9
feat: test failure fix attempt
Nov 30, 2025
90450f2
feat: test failure fix attempt
Nov 30, 2025
37c6ad9
feat: addressed review comments
Dec 2, 2025
26c42c7
feat: attempt to fix failing tests
Dec 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 110 additions & 9 deletions connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
"io"
"log/slog"
"net"
"os"
"strings"
"sync"
"syscall"
"time"

"github.com/blinklabs-io/gouroboros/connection"
Expand Down Expand Up @@ -250,6 +253,100 @@
close(c.errorChan)
}

// isConnectionReset checks if an error is a connection reset error using proper error type checking
func (c *Connection) isConnectionReset(err error) bool {
if errors.Is(err, io.EOF) {
return true
}

// Check for connection reset errors using proper error type checking
var opErr *net.OpError
if errors.As(err, &opErr) {
if syscallErr, ok := opErr.Err.(*os.SyscallError); ok {

Check failure on line 265 in connection.go

View workflow job for this annotation

GitHub Actions / lint

type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors (errorlint)
if errno, ok := syscallErr.Err.(syscall.Errno); ok {

Check failure on line 266 in connection.go

View workflow job for this annotation

GitHub Actions / lint

type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors (errorlint)
// Check for connection reset (ECONNRESET) or broken pipe (EPIPE)
return errno == syscall.ECONNRESET || errno == syscall.EPIPE
}
}
// Also check for string-based errors as fallback for edge cases
errStr := opErr.Err.Error()
return strings.Contains(errStr, "connection reset") ||
strings.Contains(errStr, "broken pipe")
}

return false
}

// checkProtocolsDone checks if the protocols are explicitly stopped by the client - treat as normal connection closure
func (c *Connection) checkProtocolsDone() bool {
// Check chain-sync protocol
if c.chainSync != nil {
if (c.chainSync.Client != nil && !c.chainSync.Client.IsDone()) ||
(c.chainSync.Server != nil && !c.chainSync.Server.IsDone()) {
return false
}
}

// Check block-fetch protocol
if c.blockFetch != nil {
if (c.blockFetch.Client != nil && !c.blockFetch.Client.IsDone()) ||
(c.blockFetch.Server != nil && !c.blockFetch.Server.IsDone()) {
return false
}
}

// Check tx-submission protocol
if c.txSubmission != nil {
if (c.txSubmission.Client != nil && !c.txSubmission.Client.IsDone()) ||
(c.txSubmission.Server != nil && !c.txSubmission.Server.IsDone()) {
return false
}
}

// Check local-state-query protocol
if c.localStateQuery != nil {
if (c.localStateQuery.Client != nil && !c.localStateQuery.Client.IsDone()) ||
(c.localStateQuery.Server != nil && !c.localStateQuery.Server.IsDone()) {
return false
}
}

// Check local-tx-monitor protocol
if c.localTxMonitor != nil {
if (c.localTxMonitor.Client != nil && !c.localTxMonitor.Client.IsDone()) ||
(c.localTxMonitor.Server != nil && !c.localTxMonitor.Server.IsDone()) {
return false
}
}

// Check local-tx-submission protocol
if c.localTxSubmission != nil {
if (c.localTxSubmission.Client != nil && !c.localTxSubmission.Client.IsDone()) ||
(c.localTxSubmission.Server != nil && !c.localTxSubmission.Server.IsDone()) {
return false
}
}

return true
}

// handleConnectionError handles connection-level errors centrally
func (c *Connection) handleConnectionError(err error) error {
if err == nil {
return nil
}

if c.checkProtocolsDone() {
return nil
}

if errors.Is(err, io.EOF) || c.isConnectionReset(err) {
return err
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block doesn't seem to be useful, since we unconditionally return err right below it


return err
}

// setupConnection establishes the muxer, configures and starts the handshake process, and initializes
// the appropriate mini-protocols
func (c *Connection) setupConnection() error {
Expand Down Expand Up @@ -285,16 +382,20 @@
if !ok {
return
}
var connErr *muxer.ConnectionClosedError
if errors.As(err, &connErr) {
// Pass through ConnectionClosedError from muxer
c.errorChan <- err
} else {
// Wrap error message to denote it comes from the muxer
c.errorChan <- fmt.Errorf("muxer error: %w", err)

// Use centralized connection error handling
if handledErr := c.handleConnectionError(err); handledErr != nil {
var connErr *muxer.ConnectionClosedError
if errors.As(handledErr, &connErr) {
// Pass through ConnectionClosedError from muxer
c.errorChan <- handledErr
} else {
// Wrap error message to denote it comes from the muxer
c.errorChan <- fmt.Errorf("muxer error: %w", handledErr)
}
// Close connection on muxer errors
c.Close()
}
// Close connection on muxer errors
c.Close()
}
}()
protoOptions := protocol.ProtocolOptions{
Expand Down
Loading
Loading