style: check error returns flagged by errcheck linter

golangci-lint's errcheck rule requires explicit handling of error
return values from Close, Write, and Logout calls. Use blank
identifier assignment for cleanup paths where errors are
intentionally discarded.
This commit is contained in:
Houmgaor
2026-02-20 21:22:01 +01:00
parent 458d8c9397
commit e899a2f790
8 changed files with 34 additions and 34 deletions

View File

@@ -22,7 +22,7 @@ func DialWithInit(addr string) (*MHFConn, error) {
// Sign and entrance servers expect 8 NULL bytes to initialize the connection. // Sign and entrance servers expect 8 NULL bytes to initialize the connection.
_, err = conn.Write(make([]byte, 8)) _, err = conn.Write(make([]byte, 8))
if err != nil { if err != nil {
conn.Close() _ = conn.Close()
return nil, fmt.Errorf("write init bytes to %s: %w", addr, err) return nil, fmt.Errorf("write init bytes to %s: %w", addr, err)
} }

View File

@@ -11,8 +11,8 @@ import (
func TestCryptConnRoundTrip(t *testing.T) { func TestCryptConnRoundTrip(t *testing.T) {
// Create an in-process TCP pipe. // Create an in-process TCP pipe.
server, client := net.Pipe() server, client := net.Pipe()
defer server.Close() defer func() { _ = server.Close() }()
defer client.Close() defer func() { _ = client.Close() }()
sender := NewCryptConn(client) sender := NewCryptConn(client)
receiver := NewCryptConn(server) receiver := NewCryptConn(server)
@@ -86,8 +86,8 @@ func TestCryptPacketHeaderRoundTrip(t *testing.T) {
// multiple sequential packets. // multiple sequential packets.
func TestMultiPacketSequence(t *testing.T) { func TestMultiPacketSequence(t *testing.T) {
server, client := net.Pipe() server, client := net.Pipe()
defer server.Close() defer func() { _ = server.Close() }()
defer client.Close() defer func() { _ = client.Close() }()
sender := NewCryptConn(client) sender := NewCryptConn(client)
receiver := NewCryptConn(server) receiver := NewCryptConn(server)
@@ -123,7 +123,7 @@ func TestDialWithInit(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer listener.Close() defer func() { _ = listener.Close() }()
done := make(chan []byte, 1) done := make(chan []byte, 1)
go func() { go func() {
@@ -131,7 +131,7 @@ func TestDialWithInit(t *testing.T) {
if err != nil { if err != nil {
return return
} }
defer conn.Close() defer func() { _ = conn.Close() }()
buf := make([]byte, 8) buf := make([]byte, 8)
_, _ = io.ReadFull(conn, buf) _, _ = io.ReadFull(conn, buf)
done <- buf done <- buf
@@ -141,7 +141,7 @@ func TestDialWithInit(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer c.Close() defer func() { _ = c.Close() }()
initBytes := <-done initBytes := <-done
for i, b := range initBytes { for i, b := range initBytes {

View File

@@ -41,7 +41,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
fmt.Println("[done] Login successful!") fmt.Println("[done] Login successful!")
result.Channel.Close() _ = result.Channel.Close()
case "lobby": case "lobby":
result, err := scenario.Login(*signAddr, *user, *pass) result, err := scenario.Login(*signAddr, *user, *pass)
@@ -51,11 +51,11 @@ func main() {
} }
if err := scenario.EnterLobby(result.Channel); err != nil { if err := scenario.EnterLobby(result.Channel); err != nil {
fmt.Fprintf(os.Stderr, "enter lobby failed: %v\n", err) fmt.Fprintf(os.Stderr, "enter lobby failed: %v\n", err)
result.Channel.Close() _ = result.Channel.Close()
os.Exit(1) os.Exit(1)
} }
fmt.Println("[done] Lobby entry successful!") fmt.Println("[done] Lobby entry successful!")
result.Channel.Close() _ = result.Channel.Close()
case "session": case "session":
result, err := scenario.Login(*signAddr, *user, *pass) result, err := scenario.Login(*signAddr, *user, *pass)
@@ -66,17 +66,17 @@ func main() {
charID := result.Sign.CharIDs[0] charID := result.Sign.CharIDs[0]
if _, err := scenario.SetupSession(result.Channel, charID); err != nil { if _, err := scenario.SetupSession(result.Channel, charID); err != nil {
fmt.Fprintf(os.Stderr, "session setup failed: %v\n", err) fmt.Fprintf(os.Stderr, "session setup failed: %v\n", err)
result.Channel.Close() _ = result.Channel.Close()
os.Exit(1) os.Exit(1)
} }
if err := scenario.EnterLobby(result.Channel); err != nil { if err := scenario.EnterLobby(result.Channel); err != nil {
fmt.Fprintf(os.Stderr, "enter lobby failed: %v\n", err) fmt.Fprintf(os.Stderr, "enter lobby failed: %v\n", err)
result.Channel.Close() _ = result.Channel.Close()
os.Exit(1) os.Exit(1)
} }
fmt.Println("[session] Connected. Press Ctrl+C to disconnect.") fmt.Println("[session] Connected. Press Ctrl+C to disconnect.")
waitForSignal() waitForSignal()
scenario.Logout(result.Channel) _ = scenario.Logout(result.Channel)
case "chat": case "chat":
result, err := scenario.Login(*signAddr, *user, *pass) result, err := scenario.Login(*signAddr, *user, *pass)
@@ -87,12 +87,12 @@ func main() {
charID := result.Sign.CharIDs[0] charID := result.Sign.CharIDs[0]
if _, err := scenario.SetupSession(result.Channel, charID); err != nil { if _, err := scenario.SetupSession(result.Channel, charID); err != nil {
fmt.Fprintf(os.Stderr, "session setup failed: %v\n", err) fmt.Fprintf(os.Stderr, "session setup failed: %v\n", err)
result.Channel.Close() _ = result.Channel.Close()
os.Exit(1) os.Exit(1)
} }
if err := scenario.EnterLobby(result.Channel); err != nil { if err := scenario.EnterLobby(result.Channel); err != nil {
fmt.Fprintf(os.Stderr, "enter lobby failed: %v\n", err) fmt.Fprintf(os.Stderr, "enter lobby failed: %v\n", err)
result.Channel.Close() _ = result.Channel.Close()
os.Exit(1) os.Exit(1)
} }
@@ -110,7 +110,7 @@ func main() {
fmt.Println("[chat] Listening for chat messages. Press Ctrl+C to disconnect.") fmt.Println("[chat] Listening for chat messages. Press Ctrl+C to disconnect.")
waitForSignal() waitForSignal()
scenario.Logout(result.Channel) _ = scenario.Logout(result.Channel)
case "quests": case "quests":
result, err := scenario.Login(*signAddr, *user, *pass) result, err := scenario.Login(*signAddr, *user, *pass)
@@ -121,23 +121,23 @@ func main() {
charID := result.Sign.CharIDs[0] charID := result.Sign.CharIDs[0]
if _, err := scenario.SetupSession(result.Channel, charID); err != nil { if _, err := scenario.SetupSession(result.Channel, charID); err != nil {
fmt.Fprintf(os.Stderr, "session setup failed: %v\n", err) fmt.Fprintf(os.Stderr, "session setup failed: %v\n", err)
result.Channel.Close() _ = result.Channel.Close()
os.Exit(1) os.Exit(1)
} }
if err := scenario.EnterLobby(result.Channel); err != nil { if err := scenario.EnterLobby(result.Channel); err != nil {
fmt.Fprintf(os.Stderr, "enter lobby failed: %v\n", err) fmt.Fprintf(os.Stderr, "enter lobby failed: %v\n", err)
result.Channel.Close() _ = result.Channel.Close()
os.Exit(1) os.Exit(1)
} }
data, err := scenario.EnumerateQuests(result.Channel, 0, 0) data, err := scenario.EnumerateQuests(result.Channel, 0, 0)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "enumerate quests failed: %v\n", err) fmt.Fprintf(os.Stderr, "enumerate quests failed: %v\n", err)
scenario.Logout(result.Channel) _ = scenario.Logout(result.Channel)
os.Exit(1) os.Exit(1)
} }
fmt.Printf("[quests] Received %d bytes of quest data\n", len(data)) fmt.Printf("[quests] Received %d bytes of quest data\n", len(data))
scenario.Logout(result.Channel) _ = scenario.Logout(result.Channel)
default: default:
fmt.Fprintf(os.Stderr, "unknown action: %s (supported: login, lobby, session, chat, quests)\n", *action) fmt.Fprintf(os.Stderr, "unknown action: %s (supported: login, lobby, session, chat, quests)\n", *action)

View File

@@ -24,7 +24,7 @@ func DoEntrance(addr string) ([]ServerEntry, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("entrance connect: %w", err) return nil, fmt.Errorf("entrance connect: %w", err)
} }
defer c.Close() defer func() { _ = c.Close() }()
// Send a minimal packet (the entrance server reads it, checks len > 5 for USR data). // Send a minimal packet (the entrance server reads it, checks len > 5 for USR data).
// An empty/short packet triggers only SV2 response. // An empty/short packet triggers only SV2 response.

View File

@@ -25,7 +25,7 @@ func DoSign(addr, username, password string) (*SignResult, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("sign connect: %w", err) return nil, fmt.Errorf("sign connect: %w", err)
} }
defer c.Close() defer func() { _ = c.Close() }()
// Build DSGN request: "DSGN:041" + \x00 + SJIS(user) + \x00 + SJIS(pass) + \x00 + \x00 // Build DSGN request: "DSGN:041" + \x00 + SJIS(user) + \x00 + SJIS(pass) + \x00 + \x00
// The server reads: null-terminated request type, null-terminated user, null-terminated pass, null-terminated unk. // The server reads: null-terminated request type, null-terminated user, null-terminated pass, null-terminated unk.

View File

@@ -58,17 +58,17 @@ func Login(signAddr, username, password string) (*LoginResult, error) {
loginPkt := protocol.BuildLoginPacket(ack, charID, sign.TokenID, sign.TokenString) loginPkt := protocol.BuildLoginPacket(ack, charID, sign.TokenID, sign.TokenString)
fmt.Printf("[channel] Sending MSG_SYS_LOGIN (charID=%d, ackHandle=%d)...\n", charID, ack) fmt.Printf("[channel] Sending MSG_SYS_LOGIN (charID=%d, ackHandle=%d)...\n", charID, ack)
if err := ch.SendPacket(loginPkt); err != nil { if err := ch.SendPacket(loginPkt); err != nil {
ch.Close() _ = ch.Close()
return nil, fmt.Errorf("channel send login: %w", err) return nil, fmt.Errorf("channel send login: %w", err)
} }
resp, err := ch.WaitForAck(ack, 10*time.Second) resp, err := ch.WaitForAck(ack, 10*time.Second)
if err != nil { if err != nil {
ch.Close() _ = ch.Close()
return nil, fmt.Errorf("channel login ack: %w", err) return nil, fmt.Errorf("channel login ack: %w", err)
} }
if resp.ErrorCode != 0 { if resp.ErrorCode != 0 {
ch.Close() _ = ch.Close()
return nil, fmt.Errorf("channel login failed: error code %d", resp.ErrorCode) return nil, fmt.Errorf("channel login failed: error code %d", resp.ErrorCode)
} }
fmt.Printf("[channel] Login ACK received (error=%d, %d bytes data)\n", fmt.Printf("[channel] Login ACK received (error=%d, %d bytes data)\n",

View File

@@ -10,7 +10,7 @@ import (
func Logout(ch *protocol.ChannelConn) error { func Logout(ch *protocol.ChannelConn) error {
fmt.Println("[logout] Sending MSG_SYS_LOGOUT...") fmt.Println("[logout] Sending MSG_SYS_LOGOUT...")
if err := ch.SendPacket(protocol.BuildLogoutPacket()); err != nil { if err := ch.SendPacket(protocol.BuildLogoutPacket()); err != nil {
ch.Close() _ = ch.Close()
return fmt.Errorf("logout send: %w", err) return fmt.Errorf("logout send: %w", err)
} }
return ch.Close() return ch.Close()

View File

@@ -59,7 +59,7 @@ func TestChannelIsolation_ShutdownDoesNotAffectOthers(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("initial connection to %s failed: %v", addr, err) t.Fatalf("initial connection to %s failed: %v", addr, err)
} }
conn.Close() _ = conn.Close()
} }
// Shut down channel 1. // Shut down channel 1.
@@ -84,7 +84,7 @@ func TestChannelIsolation_ShutdownDoesNotAffectOthers(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("%s should still accept connections after channel 1 shutdown, got: %v", tc.name, err) t.Errorf("%s should still accept connections after channel 1 shutdown, got: %v", tc.name, err)
} else { } else {
conn.Close() _ = conn.Close()
} }
} }
} }
@@ -99,7 +99,7 @@ func TestChannelIsolation_ListenerCloseDoesNotAffectOthers(t *testing.T) {
addr2 := listenerAddr(ch2) addr2 := listenerAddr(ch2)
// Forcibly close channel 1's listener (simulating unexpected failure). // Forcibly close channel 1's listener (simulating unexpected failure).
ch1.listener.Close() _ = ch1.listener.Close()
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
// Channel 2 must still work. // Channel 2 must still work.
@@ -107,7 +107,7 @@ func TestChannelIsolation_ListenerCloseDoesNotAffectOthers(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("channel 2 should still accept connections after channel 1 listener closed: %v", err) t.Fatalf("channel 2 should still accept connections after channel 1 listener closed: %v", err)
} }
conn.Close() _ = conn.Close()
} }
// TestChannelIsolation_SessionPanicDoesNotAffectChannel verifies that a panic // TestChannelIsolation_SessionPanicDoesNotAffectChannel verifies that a panic
@@ -124,9 +124,9 @@ func TestChannelIsolation_SessionPanicDoesNotAffectChannel(t *testing.T) {
// Send garbage data that will cause handlePacketGroup to hit the panic recovery. // Send garbage data that will cause handlePacketGroup to hit the panic recovery.
// The session's defer/recover should catch it without killing the channel. // The session's defer/recover should catch it without killing the channel.
conn1.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF}) _, _ = conn1.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF})
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
conn1.Close() _ = conn1.Close()
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
// The channel should still accept new connections after the panic. // The channel should still accept new connections after the panic.
@@ -134,7 +134,7 @@ func TestChannelIsolation_SessionPanicDoesNotAffectChannel(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("channel should still accept connections after session panic: %v", err) t.Fatalf("channel should still accept connections after session panic: %v", err)
} }
conn2.Close() _ = conn2.Close()
} }
// TestChannelIsolation_CrossChannelRegistryAfterShutdown verifies that the // TestChannelIsolation_CrossChannelRegistryAfterShutdown verifies that the