GPCM: Apply lint suggestions

This commit is contained in:
Palapeli 2026-04-06 07:05:59 -04:00
parent 2157575483
commit 32e7c6a3f8
No known key found for this signature in database
GPG Key ID: 1FFE8F556A474925
7 changed files with 214 additions and 156 deletions

6
go.mod
View File

@ -13,15 +13,15 @@ require (
require (
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.14.3 // indirect
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6 // indirect
github.com/jackc/pgconn v1.14.3
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgtype v1.14.4 // indirect
github.com/jackc/puddle v1.3.0 // indirect
github.com/linkdata/deadlock v0.5.5 // indirect
github.com/linkdata/deadlock v0.5.5
github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/text v0.31.0 // indirect

View File

@ -419,67 +419,77 @@ func (err GPError) GetMessageTranslate(gameName string, region byte, lang byte,
command.OtherValues["fatal"] = ""
}
if err.Fatal && err.WWFCMessage.ErrorCode != 0 {
switch gameName {
case "mariokartwii":
reason := err.Reason
wwfcMessage := err.WWFCMessage
if !err.Fatal || err.WWFCMessage.ErrorCode == 0 {
return common.CreateGameSpyMessage(command), err.WWFCMessage.ErrorCode
}
if reason == "" {
reason = "None provided."
errMsg := ""
reason := ""
var wwfcMessage *WWFCErrorMessage
switch gameName {
case "mariokartwii":
reason = err.Reason
wwfcMessage = &err.WWFCMessage
engMsg := err.WWFCMessage.MessageRMC[LangEnglish]
if reason == "" {
reason = "None provided."
if engMsg == WWFCMsgKickedCustom.MessageRMC[LangEnglish] {
wwfcMessage = WWFCMsgKickedModerator
} else if engMsg == WWFCMsgProfileRestrictedCustom.MessageRMC[LangEnglish] {
wwfcMessage = WWFCMsgProfileRestricted
} else if engMsg == WWFCMsgProfileRestrictedNowCustom.MessageRMC[LangEnglish] {
wwfcMessage = WWFCMsgProfileRestrictedNow
}
}
errMsg := wwfcMessage.MessageRMC[lang]
if errMsg == "" && lang != LangEnglish {
if lang == LangSpanishEU {
errMsg = wwfcMessage.MessageRMC[LangSpanish]
} else if lang == LangFrenchEU {
errMsg = wwfcMessage.MessageRMC[LangFrench]
}
if errMsg == "" {
errMsg = wwfcMessage.MessageRMC[LangEnglish]
}
}
if errMsg != "" {
errMsg = fmt.Sprintf(errMsg, wwfcMessage.ErrorCode, ngid, reason)
errMsgUTF16 := utf16.Encode([]rune(errMsg))
errMsgByteArray := common.UTF16ToByteArray(errMsgUTF16)
command.OtherValues["wl:errmsg"] = common.Base64DwcEncoding.EncodeToString(errMsgByteArray)
switch engMsg := err.WWFCMessage.MessageRMC[LangEnglish]; engMsg {
case WWFCMsgKickedCustom.MessageRMC[LangEnglish]:
wwfcMessage = &WWFCMsgKickedModerator
case WWFCMsgProfileRestrictedCustom.MessageRMC[LangEnglish]:
wwfcMessage = &WWFCMsgProfileRestricted
case WWFCMsgProfileRestrictedNowCustom.MessageRMC[LangEnglish]:
wwfcMessage = &WWFCMsgProfileRestrictedNow
}
}
command.OtherValues["wl:err"] = strconv.Itoa(err.WWFCMessage.ErrorCode)
errMsg = wwfcMessage.MessageRMC[lang]
if errMsg == "" || lang == LangEnglish {
break
}
switch lang {
case LangSpanishEU:
errMsg = wwfcMessage.MessageRMC[LangSpanish]
case LangFrenchEU:
errMsg = wwfcMessage.MessageRMC[LangFrench]
}
if errMsg == "" {
errMsg = wwfcMessage.MessageRMC[LangEnglish]
}
}
if errMsg != "" && wwfcMessage != nil {
errMsg = fmt.Sprintf(errMsg, wwfcMessage.ErrorCode, ngid, reason)
errMsgUTF16 := utf16.Encode([]rune(errMsg))
errMsgByteArray := common.UTF16ToByteArray(errMsgUTF16)
command.OtherValues["wl:errmsg"] = common.Base64DwcEncoding.EncodeToString(errMsgByteArray)
}
command.OtherValues["wl:err"] = strconv.Itoa(err.WWFCMessage.ErrorCode)
return common.CreateGameSpyMessage(command), err.WWFCMessage.ErrorCode
}
func (g *GameSpySession) replyError(err GPError) {
logging.Error(g.ModuleName, "Reply error:", err.ErrorString)
func (g *GameSpySession) replyError(gpErr GPError) {
logging.Error(g.ModuleName, "Reply error:", gpErr.ErrorString)
if !g.LoginInfoSet {
msg := err.GetMessage()
msg := gpErr.GetMessage()
// logging.Info(g.ModuleName, "Sending error message:", msg)
common.SendPacket(ServerName, g.ConnIndex, []byte(msg))
if err.Fatal {
common.CloseConnection(ServerName, g.ConnIndex)
err := common.SendPacket(ServerName, g.ConnIndex, []byte(msg))
if gpErr.Fatal || err != nil {
if err != nil {
logging.Error("GPCM", "Failed to send packet:", err)
}
common.ShouldNotError(common.CloseConnection(ServerName, g.ConnIndex))
}
logging.Event("gpcm_returned_error", map[string]any{
"profile_id": g.User.ProfileId,
"error_code": err.ErrorCode,
"error_string": err.ErrorString,
"fatal": err.Fatal,
"error_code": gpErr.ErrorCode,
"error_string": gpErr.ErrorString,
"fatal": gpErr.Fatal,
})
return
}
@ -489,18 +499,21 @@ func (g *GameSpySession) replyError(err GPError) {
deviceId = g.User.NgDeviceId[0]
}
msg, wwfcErrorCode := err.GetMessageTranslate(g.GameName, g.Region, g.Language, g.ConsoleFriendCode, deviceId)
msg, wwfcErrorCode := gpErr.GetMessageTranslate(g.GameName, g.Region, g.Language, g.ConsoleFriendCode, deviceId)
// logging.Info(g.ModuleName, "Sending error message:", msg)
common.SendPacket(ServerName, g.ConnIndex, []byte(msg))
if err.Fatal {
common.CloseConnection(ServerName, g.ConnIndex)
err := common.SendPacket(ServerName, g.ConnIndex, []byte(msg))
if gpErr.Fatal || err != nil {
if err != nil {
logging.Error("GPCM", "Failed to send packet:", err)
}
common.ShouldNotError(common.CloseConnection(ServerName, g.ConnIndex))
}
logging.Event("gpcm_returned_error", map[string]any{
"profile_id": g.User.ProfileId,
"error_code": err.ErrorCode,
"error_string": err.ErrorString,
"fatal": err.Fatal,
"error_code": gpErr.ErrorCode,
"error_string": gpErr.ErrorString,
"fatal": gpErr.Fatal,
"wiilink_error_code": wwfcErrorCode,
})
}

View File

@ -1,7 +1,6 @@
package gpcm
import (
"errors"
"strconv"
"strings"
"wwfc/common"
@ -11,19 +10,18 @@ import (
"github.com/logrusorgru/aurora/v3"
)
func removeFromUint32Array(arrayPointer *[]uint32, index int) error {
func removeFromUint32Array(arrayPointer *[]uint32, index int) {
array := *arrayPointer
arrayLength := len(array)
if index < 0 || index >= arrayLength {
return errors.New("index is out of bounds")
return // Ignore?
}
lastIndex := arrayLength - 1
array[index] = array[lastIndex]
*arrayPointer = array[:lastIndex]
return nil
}
func (g *GameSpySession) isFriendAdded(profileId uint32) bool {
@ -261,7 +259,10 @@ func sendMessageToSession(msgType string, from uint32, session *GameSpySession,
"msg": msg,
},
})
common.SendPacket(ServerName, session.ConnIndex, []byte(message))
if err := common.SendPacket(ServerName, session.ConnIndex, []byte(message)); err != nil {
logging.Error("GPCM", "Failed to send packet:", err)
common.ShouldNotError(common.CloseConnection(ServerName, session.ConnIndex))
}
}
func sendMessageToSessionBuffer(msgType string, from uint32, session *GameSpySession, msg string) {

View File

@ -27,7 +27,7 @@ func kickPlayer(profileID uint32, reason string) {
case "network_error":
// No error message
common.CloseConnection(ServerName, session.ConnIndex)
common.ShouldNotError(common.CloseConnection(ServerName, session.ConnIndex))
return
}

View File

@ -247,7 +247,12 @@ func (g *GameSpySession) login(command common.GameSpyCommand) {
deviceAuth := false
defaultKey := false
if g.UnitCode == UnitCodeWii {
switch g.UnitCode {
case UnitCodeDS:
g.NeedsExploit = common.DoesGameNeedExploit(g.GameName)
deviceAuth = true
case UnitCodeWii:
if isLocalhost && !payloadVerExists && !signatureExists {
// Players using the DNS, need patching using a QR2 exploit
if !common.DoesGameNeedExploit(g.GameName) {
@ -269,10 +274,8 @@ func (g *GameSpySession) login(command common.GameSpyCommand) {
}
deviceAuth = true
}
} else if g.UnitCode == UnitCodeDS {
g.NeedsExploit = common.DoesGameNeedExploit(g.GameName)
deviceAuth = true
} else {
default:
logging.Error(g.ModuleName, "Invalid unit code specified:", aurora.Cyan(unitcd))
g.replyError(ErrLogin)
return
@ -393,7 +396,10 @@ func (g *GameSpySession) login(command common.GameSpyCommand) {
OtherValues: otherValues,
})
common.SendPacket(ServerName, g.ConnIndex, []byte(payload))
if err := common.SendPacket(ServerName, g.ConnIndex, []byte(payload)); err != nil {
logging.Error("GPCM", "Failed to send login response packet")
panic(err)
}
logging.Event(
"logged_in",
@ -505,21 +511,22 @@ func (g *GameSpySession) performLoginWithDatabase(userId uint64, gsbrCode string
if err != nil {
logging.Error(g.ModuleName, "DB error:", err)
if err == database.ErrProfileIDInUse {
switch err {
case database.ErrProfileIDInUse:
g.replyError(GPError{
ErrorCode: ErrLogin.ErrorCode,
ErrorString: "The profile ID is already in use.",
Fatal: true,
WWFCMessage: WWFCMsgProfileIDInUse,
})
} else if err == database.ErrReservedProfileIDRange {
case database.ErrReservedProfileIDRange:
g.replyError(GPError{
ErrorCode: ErrLogin.ErrorCode,
ErrorString: "The profile ID is in a reserved range.",
Fatal: true,
WWFCMessage: WWFCMsgProfileIDInvalid,
})
} else if err == database.ErrDeviceIDMismatch {
case database.ErrDeviceIDMismatch:
if strings.HasPrefix(g.HostPlatform, "Dolphin") {
g.replyError(GPError{
ErrorCode: ErrLogin.ErrorCode,
@ -535,7 +542,7 @@ func (g *GameSpySession) performLoginWithDatabase(userId uint64, gsbrCode string
WWFCMessage: WWFCMsgConsoleMismatch,
})
}
} else if err == database.ErrProhibitedDeviceID {
case database.ErrProhibitedDeviceID:
if strings.HasPrefix(g.HostPlatform, "Dolphin") {
g.replyError(GPError{
ErrorCode: ErrLogin.ErrorCode,
@ -551,7 +558,7 @@ func (g *GameSpySession) performLoginWithDatabase(userId uint64, gsbrCode string
WWFCMessage: WWFCMsgUnknownLoginError,
})
}
} else if err == database.ErrProfileBannedTOS {
case database.ErrProfileBannedTOS:
g.replyError(GPError{
ErrorCode: ErrLogin.ErrorCode,
ErrorString: "The profile is banned from the service. Reason: " + user.BanReason,
@ -559,7 +566,7 @@ func (g *GameSpySession) performLoginWithDatabase(userId uint64, gsbrCode string
WWFCMessage: WWFCMsgProfileBannedTOS,
Reason: user.BanReason,
})
} else {
default:
g.replyError(GPError{
ErrorCode: ErrLogin.ErrorCode,
ErrorString: "There was an error logging in to the GP backend.",

View File

@ -169,7 +169,11 @@ func NewConnection(index uint64, address string) {
"id": "1",
},
})
common.SendPacket(ServerName, index, []byte(payload))
if err := common.SendPacket(ServerName, index, []byte(payload)); err != nil {
logging.Error("GPCM", "Failed to send login challenge packet:", err)
_ = common.CloseConnection(ServerName, index)
return
}
logging.Notice(session.ModuleName, "Connection established from", address)
@ -185,6 +189,7 @@ func HandlePacket(index uint64, data []byte) {
if session == nil {
logging.Error("GPCM", "Cannot find session for this connection index:", aurora.Cyan(index))
_ = common.CloseConnection(ServerName, index)
return
}
@ -238,7 +243,7 @@ func HandlePacket(index uint64, data []byte) {
// Commands must be handled in a certain order, not in the order supplied by the client
commands = session.handleCommand("ka", commands, func(command common.GameSpyCommand) {
common.SendPacket(ServerName, session.ConnIndex, []byte(`\ka\\final\`))
_ = common.SendPacket(ServerName, session.ConnIndex, []byte(`\ka\\final\`))
})
commands = session.handleCommand("login", commands, session.login)
commands = session.handleCommand("wl:exlogin", commands, session.exLogin)
@ -278,8 +283,11 @@ func HandlePacket(index uint64, data []byte) {
data = append(data, session.WriteBuffer[c])
}
common.SendPacket(ServerName, session.ConnIndex, data)
session.WriteBuffer = ""
if err := common.SendPacket(ServerName, session.ConnIndex, data); err != nil {
logging.Error(session.ModuleName, "Failed to send response packet:", err)
} else {
session.WriteBuffer = ""
}
}
}
@ -323,7 +331,7 @@ func saveState() error {
defer mutex.Unlock()
err = encoder.Encode(sessions)
file.Close()
common.ShouldNotError(file.Close())
return err
}
@ -339,7 +347,7 @@ func loadState() error {
defer mutex.Unlock()
err = decoder.Decode(&sessions)
file.Close()
common.ShouldNotError(file.Close())
if err != nil {
return err
}

View File

@ -162,9 +162,10 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) {
return
}
if cmd == common.MatchReservation {
switch cmd {
case common.MatchReservation:
g.QR2IP = uint64(msgMatchData.Reservation.PublicIP) | (uint64(msgMatchData.Reservation.PublicPort) << 32)
} else if cmd == common.MatchResvOK {
case common.MatchResvOK:
g.QR2IP = uint64(msgMatchData.ResvOK.PublicIP) | (uint64(msgMatchData.ResvOK.PublicPort) << 32)
}
@ -193,90 +194,29 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) {
sameAddress := strings.Split(g.RemoteAddr, ":")[0] == strings.Split(toSession.RemoteAddr, ":")[0]
if cmd == common.MatchReservation {
if g.QR2IP == 0 {
logging.Error(g.ModuleName, "Missing QR2 IP")
g.replyError(ErrMessage)
return
}
ok = true
switch cmd {
case common.MatchReservation:
ok = g.mungeMatchReservation(toSession, &msgMatchData, uint32(toProfileId), sameAddress)
if g.User.Restricted || toSession.User.Restricted {
// Check with QR2 if the room is public or private
resvError := qr2.CheckGPReservationAllowed(g.QR2IP, g.User.ProfileId, uint32(toProfileId), msgMatchData.Reservation.MatchType)
if resvError != "ok" {
if resvError == "restricted" || resvError == "restricted_join" {
logging.Error(g.ModuleName, "RESERVATION: Restricted user tried to connect to public room")
case common.MatchResvOK, common.MatchResvDeny, common.MatchResvWait:
ok = g.mungeMatchReservationResult(cmd, toSession, &msgMatchData, uint32(toProfileId), sameAddress)
// Kick the player(s)
if g.User.Restricted {
kickPlayer(toSession.User.ProfileId, resvError)
}
if toSession.User.Restricted {
kickPlayer(g.User.ProfileId, resvError)
}
}
logging.Warn(g.ModuleName, "RESERVATION: Not allowed:", resvError)
// Otherwise generic error?
return
}
}
if !sameAddress {
searchId := qr2.GetSearchID(g.QR2IP)
msgMatchData.Reservation.PublicIP = uint32(searchId & 0xffffffff)
msgMatchData.Reservation.PublicPort = uint16(searchId >> 32)
msgMatchData.Reservation.LocalIP = 0
msgMatchData.Reservation.LocalPort = 0
}
} else if cmd == common.MatchResvOK || cmd == common.MatchResvDeny || cmd == common.MatchResvWait {
if toSession.ReservationPID != g.User.ProfileId || toSession.Reservation.Reservation == nil {
logging.Error(g.ModuleName, "Destination", aurora.Cyan(toProfileId), "has no reservation with the sender")
// Allow the message through anyway to avoid a room deadlock
}
if toSession.Reservation.Version != msgMatchData.Version {
logging.Error(g.ModuleName, "Reservation version mismatch")
g.replyError(ErrMessage)
return
}
if cmd == common.MatchResvOK {
if g.QR2IP == 0 || toSession.QR2IP == 0 {
logging.Error(g.ModuleName, "Missing QR2 IP")
g.replyError(ErrMessage)
return
}
if !qr2.ProcessGPResvOK(msgMatchData.Version, *toSession.Reservation.Reservation, *msgMatchData.ResvOK, g.QR2IP, g.User.ProfileId, toSession.QR2IP, uint32(toProfileId)) {
g.replyError(ErrMessage)
return
}
if !sameAddress {
searchId := qr2.GetSearchID(g.QR2IP)
if searchId == 0 {
logging.Error(g.ModuleName, "Could not get QR2 search ID for IP", aurora.Cyan(fmt.Sprintf("%016x", g.QR2IP)))
g.replyError(ErrMessage)
return
}
msgMatchData.ResvOK.PublicIP = uint32(searchId & 0xffffffff)
msgMatchData.ResvOK.PublicPort = uint16(searchId >> 32)
}
} else if toSession.ReservationPID == g.User.ProfileId {
toSession.ReservationPID = 0
}
} else if cmd == common.MatchTellAddr {
case common.MatchTellAddr:
if g.QR2IP == 0 || toSession.QR2IP == 0 {
logging.Error(g.ModuleName, "Missing QR2 IP")
g.replyError(ErrMessage)
return
ok = false
break
}
qr2.ProcessGPTellAddr(g.User.ProfileId, g.QR2IP, toSession.User.ProfileId, toSession.QR2IP)
}
if !ok {
return
}
newMsg, ok := common.EncodeMatchCommand(cmd, msgMatchData)
if !ok || len(newMsg) > 0x200 || (len(newMsg)%4) != 0 {
logging.Error(g.ModuleName, "Failed to encode match command; message:", msg)
@ -347,9 +287,98 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) {
},
})
common.SendPacket(ServerName, toSession.ConnIndex, []byte(message))
if err := common.SendPacket(ServerName, toSession.ConnIndex, []byte(message)); err != nil {
logging.Error(g.ModuleName, "Failed to send packet:", err)
}
// Append sender's profile ID to dest's RecvStatusFromList
toSession.RecvStatusFromList = append(toSession.RecvStatusFromList, g.User.ProfileId)
}
func (g *GameSpySession) mungeMatchReservation(toSession *GameSpySession, msgMatchData *common.MatchCommandData, toProfileId uint32, sameAddress bool) bool {
if g.QR2IP == 0 {
logging.Error(g.ModuleName, "Missing QR2 IP")
g.replyError(ErrMessage)
return false
}
if !sameAddress {
searchId := qr2.GetSearchID(g.QR2IP)
msgMatchData.Reservation.PublicIP = uint32(searchId & 0xffffffff)
msgMatchData.Reservation.PublicPort = uint16(searchId >> 32)
msgMatchData.Reservation.LocalIP = 0
msgMatchData.Reservation.LocalPort = 0
}
if !g.User.Restricted && !toSession.User.Restricted {
return true
}
// Check with QR2 if the room is public or private
resvError := qr2.CheckGPReservationAllowed(g.QR2IP, g.User.ProfileId, uint32(toProfileId), msgMatchData.Reservation.MatchType)
if resvError == "ok" {
return true
}
// Figure out which error to return
if resvError == "restricted" || resvError == "restricted_join" {
logging.Error(g.ModuleName, "RESERVATION: Restricted user tried to connect to public room")
// Kick the player(s)
if g.User.Restricted {
kickPlayer(toSession.User.ProfileId, resvError)
}
if toSession.User.Restricted {
kickPlayer(g.User.ProfileId, resvError)
}
}
logging.Warn(g.ModuleName, "RESERVATION: Not allowed:", resvError)
// Otherwise generic error?
return false
}
func (g *GameSpySession) mungeMatchReservationResult(cmd byte, toSession *GameSpySession, msgMatchData *common.MatchCommandData, toProfileId uint32, sameAddress bool) bool {
if toSession.ReservationPID != g.User.ProfileId || toSession.Reservation.Reservation == nil {
logging.Error(g.ModuleName, "Destination", aurora.Cyan(toProfileId), "has no reservation with the sender")
// Allow the message through anyway to avoid a room deadlock
}
if toSession.Reservation.Version != msgMatchData.Version {
logging.Error(g.ModuleName, "Reservation version mismatch")
g.replyError(ErrMessage)
return false
}
if cmd != common.MatchResvOK {
if toSession.ReservationPID == g.User.ProfileId {
toSession.ReservationPID = 0
}
return true
}
if g.QR2IP == 0 || toSession.QR2IP == 0 {
logging.Error(g.ModuleName, "Missing QR2 IP")
g.replyError(ErrMessage)
return false
}
if !qr2.ProcessGPResvOK(msgMatchData.Version, *toSession.Reservation.Reservation, *msgMatchData.ResvOK, g.QR2IP, g.User.ProfileId, toSession.QR2IP, uint32(toProfileId)) {
g.replyError(ErrMessage)
return false
}
if !sameAddress {
searchId := qr2.GetSearchID(g.QR2IP)
if searchId == 0 {
logging.Error(g.ModuleName, "Could not get QR2 search ID for IP", aurora.Cyan(fmt.Sprintf("%016x", g.QR2IP)))
g.replyError(ErrMessage)
return false
}
msgMatchData.ResvOK.PublicIP = uint32(searchId & 0xffffffff)
msgMatchData.ResvOK.PublicPort = uint16(searchId >> 32)
}
return true
}