Go-ify and improve some code

This commit is contained in:
mkwcat 2024-02-20 09:37:29 -05:00
parent 825b67405b
commit 08f85da5f4
No known key found for this signature in database
GPG Key ID: 7A505679CE9E7AA9
16 changed files with 94 additions and 68 deletions

View File

@ -84,7 +84,9 @@ func MarshalNASAuthToken(gamecd string, userid uint64, gsbrcd string, cfc uint64
return "NDS" + Base64DwcEncoding.EncodeToString(blob), challenge
}
func UnmarshalNASAuthToken(token string) (err error, gamecd string, issuetime time.Time, userid uint64, gsbrcd string, cfc uint64, region byte, lang byte, ingamesn string, challenge string, unitcd byte, isLocalhost bool) {
func UnmarshalNASAuthToken(token string) (gamecd string, issuetime time.Time, userid uint64, gsbrcd string, cfc uint64, region byte, lang byte, ingamesn string, challenge string, unitcd byte, isLocalhost bool, err error) {
err = nil
if !strings.HasPrefix(token, "NDS") {
err = errors.New("invalid auth token prefix")
return
@ -140,7 +142,9 @@ func MarshalGPCMLoginTicket(profileId uint32) string {
return Base64DwcEncoding.EncodeToString(blob)
}
func UnmarshalGPCMLoginTicket(ticket string) (err error, profileId uint32, issuetime time.Time) {
func UnmarshalGPCMLoginTicket(ticket string) (profileId uint32, issuetime time.Time, err error) {
err = nil
blob, err := Base64DwcEncoding.DecodeString(ticket)
if err != nil {
return

View File

@ -13,12 +13,12 @@ type GameSpyCommand struct {
}
var (
InvalidGameSpyCommand = errors.New("invalid GameSpy command received")
ErrInvalidGameSpyCommand = errors.New("invalid GameSpy command received")
)
func ParseGameSpyMessage(msg string) ([]GameSpyCommand, error) {
if !strings.Contains(msg, `\final\`) {
return nil, InvalidGameSpyCommand
return nil, ErrInvalidGameSpyCommand
}
var commands []GameSpyCommand
@ -31,7 +31,7 @@ func ParseGameSpyMessage(msg string) ([]GameSpyCommand, error) {
for len(msg) > 0 && string(msg[0]) == `\` {
keyEnd := strings.Index(msg[1:], `\`) + 1
if keyEnd < 2 {
return nil, InvalidGameSpyCommand
return nil, ErrInvalidGameSpyCommand
}
key := msg[1:keyEnd]

View File

@ -689,8 +689,6 @@ func EncodeMatchCommand(command byte, data MatchCommandData) ([]byte, bool) {
logging.Info("Common", "Unknown match command:", aurora.Cyan(command), "data:", data.Other)
return data.Other, true
}
return []byte{}, false
}
func LogMatchCommand(moduleName string, dest string, command byte, data MatchCommandData) {

View File

@ -62,7 +62,7 @@ func (g *GameStatsSession) authp(command common.GameSpyCommand) {
return
}
err, _, issueTime, userId, gsbrcd, _, _, _, _, _, _, _ := common.UnmarshalNASAuthToken(authToken)
_, issueTime, userId, gsbrcd, _, _, _, _, _, _, _, err := common.UnmarshalNASAuthToken(authToken)
if err != nil {
logging.Error(g.ModuleName, "Error unmarshalling authtoken:", err.Error())
g.Write(errorCmd)

View File

@ -66,10 +66,10 @@ func (g *GameSpySession) getAuthorizedFriendIndex(profileId uint32) int {
}
const (
addFriendMessage = "\r\n\r\n|signed|00000000000000000000000000000000"
// addFriendMessage = "\r\n\r\n|signed|00000000000000000000000000000000"
// TODO: Check if this is needed for any game, it sends via bm 1
authFriendMessage = "I have authorized your request to add me to your list"
// authFriendMessage = "I have authorized your request to add me to your list"
logOutMessage = "|s|0|ss|Offline|ls||ip|0|p|0|qm|0"
)
@ -145,17 +145,6 @@ func (g *GameSpySession) addFriend(command common.GameSpyCommand) {
g.exchangeFriendStatus(uint32(newProfileId))
}
func (g *GameSpySession) sendFriendRequests() {
mutex.Lock()
defer mutex.Unlock()
for _, newSession := range sessions {
if newSession.isFriendAdded(g.User.ProfileId) {
sendMessageToSessionBuffer("2", g.User.ProfileId, newSession, addFriendMessage)
}
}
}
func (g *GameSpySession) removeFriend(command common.GameSpyCommand) {
strDelProfileID := command.OtherValues["delprofileid"]
delProfileID64, err := strconv.ParseUint(strDelProfileID, 10, 32)
@ -481,8 +470,7 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) {
} 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")
g.replyError(ErrMessage)
return
// Allow the message through anyway to avoid a room deadlock
}
if toSession.Reservation.Version != msgMatchData.Version {

View File

@ -156,7 +156,7 @@ func (g *GameSpySession) login(command common.GameSpyCommand) {
return
}
err, gamecd, issueTime, userId, gsbrcd, cfc, region, lang, ingamesn, challenge, unitcd, isLocalhost := common.UnmarshalNASAuthToken(authToken)
gamecd, issueTime, userId, gsbrcd, cfc, region, lang, ingamesn, challenge, unitcd, isLocalhost, err := common.UnmarshalNASAuthToken(authToken)
if err != nil {
g.replyError(ErrLogin)
return

View File

@ -196,7 +196,7 @@ func handleRequest(conn net.Conn) {
commands = session.handleCommand("wwfc_exlogin", commands, session.exLogin)
commands = session.ignoreCommand("logout", commands)
if len(commands) != 0 && session.LoggedIn == false {
if len(commands) != 0 && !session.LoggedIn {
logging.Error(session.ModuleName, "Attempt to run command before login:", aurora.Cyan(commands[0]))
session.replyError(ErrNotLoggedIn)
return

View File

@ -32,7 +32,6 @@ func (g *GameSpySession) handleWWFCReport(command common.GameSpyCommand) {
}
qr2.ProcessUSER(g.User.ProfileId, g.QR2IP, packet)
break
case "mkw_malicious_packet":
if g.GameName != "mariokartwii" {
@ -47,7 +46,6 @@ func (g *GameSpySession) handleWWFCReport(command common.GameSpyCommand) {
}
logging.Warn(g.ModuleName, "Malicious packet from", aurora.BrightCyan(strconv.FormatUint(profileId, 10)))
break
}
}
}

View File

@ -9,6 +9,7 @@ import (
"time"
"wwfc/common"
"wwfc/logging"
"wwfc/qr2"
"github.com/logrusorgru/aurora/v3"
)
@ -186,78 +187,60 @@ func handleConnection(conn net.PacketConn, addr net.Addr, buffer []byte) {
switch command {
default:
logging.Error(moduleName, "Received unknown command type:", aurora.Cyan(command))
break
case NNInitRequest:
// logging.Info(moduleName, "Command:", aurora.Yellow("NN_INIT"))
session.handleInit(conn, addr, buffer[12:], moduleName, version)
break
case NNInitReply:
logging.Warn(moduleName, "Received server command:", aurora.Yellow("NN_INITACK"))
break
case NNErtTestRequest:
logging.Warn(moduleName, "Received server command:", aurora.Yellow("NN_ERTTEST"))
break
case NNErtTestReply:
logging.Info(moduleName, "Command:", aurora.Yellow("NN_ERTACK"))
break
case NNStateUpdate:
logging.Info(moduleName, "Command:", aurora.Yellow("NN_STATEUPDATE"))
break
case NNConnectRequest:
logging.Warn(moduleName, "Received server command:", aurora.Yellow("NN_CONNECT"))
break
case NNConnectReply:
// logging.Info(moduleName, "Command:", aurora.Yellow("NN_CONNECT_ACK"))
session.handleConnectReply(conn, addr, buffer[12:], moduleName, version)
break
case NNConnectPing:
logging.Info(moduleName, "Command:", aurora.Yellow("NN_CONNECT_PING"))
break
case NNBackupTestRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("NN_BACKUP_TEST"))
break
case NNBackupTestReply:
logging.Warn(moduleName, "Received server command:", aurora.Yellow("NN_BACKUP_ACK"))
break
case NNAddressCheckRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("NN_ADDRESS_CHECK"))
break
case NNAddressCheckReply:
logging.Warn(moduleName, "Received server command:", aurora.Yellow("NN_ADDRESS_REPLY"))
break
case NNNatifyRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("NN_NATIFY_REQUEST"))
break
case NNReportRequest:
// logging.Info(moduleName, "Command:", aurora.Yellow("NN_REPORT"))
session.handleReport(conn, addr, buffer[12:], moduleName, version)
break
case NNReportReply:
logging.Warn(moduleName, "Received server command:", aurora.Yellow("NN_REPORT_ACK"))
break
case NNPreInitRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("NN_PREINIT"))
break
case NNPreInitReply:
logging.Warn(moduleName, "Received server command:", aurora.Yellow("NN_PREINIT_ACK"))
break
}
}
@ -471,8 +454,11 @@ func (session *NATNEGSession) handleReport(conn net.PacketConn, addr net.Addr, b
if client, exists := session.Clients[clientIndex]; exists {
client.Connected[client.ConnectingIndex] = true
connecting := session.Clients[client.ConnectingIndex]
client.ConnectingIndex = clientIndex
client.ConnectAck = false
qr2.ProcessNATNEGReport(result, client.ServerIP, connecting.ServerIP)
}
// Send remaining requests

View File

@ -5,6 +5,7 @@ import (
"net"
"strconv"
"strings"
"time"
"wwfc/common"
)
@ -40,5 +41,20 @@ func sendChallenge(conn net.PacketConn, addr net.Addr, session Session, lookupAd
response = append(response, []byte(challenge)...)
response = append(response, 0)
conn.WriteTo(response, addr)
go func() {
for {
conn.WriteTo(response, addr)
time.Sleep(1 * time.Second)
mutex.Lock()
session, ok := sessions[lookupAddr]
if !ok || session.Authenticated || session.LastKeepAlive < time.Now().Unix()-60 {
mutex.Unlock()
return
}
addr = session.Addr
mutex.Unlock()
}
}()
}

View File

@ -258,6 +258,41 @@ func CheckGPReservationAllowed(senderIP uint64, senderPid uint32, destPid uint32
return checkReservationAllowed(moduleName, from, to, joinType)
}
func ProcessNATNEGReport(result byte, ip1 string, ip2 string) {
moduleName := "QR2:NATNEGReport"
ip1Lookup := makeLookupAddr(ip1)
ip2Lookup := makeLookupAddr(ip2)
mutex.Lock()
defer mutex.Unlock()
session1 := sessions[ip1Lookup]
if session1 == nil {
logging.Warn(moduleName, "Received NATNEG report for non-existent IP", aurora.Cyan(ip1))
return
}
session2 := sessions[ip2Lookup]
if session2 == nil {
logging.Warn(moduleName, "Received NATNEG report for non-existent IP", aurora.Cyan(ip2))
return
}
if session1.GroupPointer == nil || session1.GroupPointer != session2.GroupPointer {
logging.Warn(moduleName, "Received NATNEG report for two IPs in different groups")
return
}
resultString := "2"
if result == 1 {
resultString = "1"
}
session1.Data["+conn_"+session2.Data["+joinindex"]] = resultString
session2.Data["+conn_"+session1.Data["+joinindex"]] = resultString
}
func ProcessUSER(senderPid uint32, senderIP uint64, packet []byte) {
moduleName := "QR2:ProcessUSER/" + strconv.FormatUint(uint64(senderPid), 10)

View File

@ -79,7 +79,6 @@ func handleConnection(conn net.PacketConn, addr net.Addr, buffer []byte) {
switch packetType {
case QueryRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("QUERY"))
break
case ChallengeRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("CHALLENGE"))
@ -94,24 +93,19 @@ func handleConnection(conn net.PacketConn, addr net.Addr, buffer []byte) {
} else {
mutex.Unlock()
}
break
case EchoRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("ECHO"))
break
case HeartbeatRequest:
// logging.Info(moduleName, "Command:", aurora.Yellow("HEARTBEAT"))
heartbeat(moduleName, conn, addr, buffer)
break
case AddErrorRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("ADDERROR"))
break
case EchoResponseRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("ECHO_RESPONSE"))
break
case ClientMessageRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("CLIENT_MESSAGE"))
@ -144,7 +138,6 @@ func handleConnection(conn net.PacketConn, addr net.Addr, buffer []byte) {
case ClientRegisteredReply:
logging.Info(moduleName, "Command:", aurora.Yellow("CLIENT_REGISTERED"))
break
case ClientExploitReply:
logging.Info(moduleName, "Command:", aurora.Yellow("CLIENT_EXPLOIT_ACK"))
@ -153,7 +146,6 @@ func handleConnection(conn net.PacketConn, addr net.Addr, buffer []byte) {
if login := session.Login; login != nil {
login.NeedsExploit = false
}
break
default:
logging.Error(moduleName, "Unknown command:", aurora.Yellow(buffer[0]))

View File

@ -260,7 +260,9 @@ func SendClientMessage(senderIP string, destSearchID uint64, message []byte) {
switch s.Fetch(true) {
case &timeWaker:
timeOutCount++
if timeOutCount <= 8 {
// Enforce a 10 second timeout
if timeOutCount <= 10 {
break
}
@ -332,8 +334,11 @@ func processClientMessage(moduleName string, sender, receiver *Session, message
sender.ReservationID = receiver.SearchID
} else if cmd == common.MatchResvOK || cmd == common.MatchResvDeny || cmd == common.MatchResvWait {
if receiver.ReservationID != sender.SearchID || receiver.Reservation.Reservation == nil {
logging.Error(moduleName, "Destination has no reservation with the sender")
return
logging.Warn(moduleName, "Destination has no reservation with the sender")
if receiver.GroupPointer == nil || receiver.GroupPointer != sender.GroupPointer {
return
}
// Allow the message through anyway to avoid a room deadlock
}
if receiver.Reservation.Version != matchData.Version {

View File

@ -52,6 +52,8 @@ func removeSession(addr uint64) {
return
}
session.MessageAckWaker.Assert()
if session.GroupPointer != nil {
session.removeFromGroup()
}
@ -84,6 +86,16 @@ func (session *Session) removeFromGroup() {
session.GroupPointer.findNewServer()
}
for player := range session.GroupPointer.Players {
delete(player.Data, "+conn_"+session.Data["+joinindex"])
}
for field := range session.Data {
if strings.HasPrefix(field, "+conn_") {
delete(session.Data, field)
}
}
session.GroupPointer = nil
}

View File

@ -42,6 +42,5 @@ func HandleRequest(w http.ResponseWriter, r *http.Request) {
case "/SakeStorageServer/StorageServer.asmx":
moduleName := "SAKE:Storage:" + r.RemoteAddr
handleStorageRequest(moduleName, w, r)
break
}
}

View File

@ -147,19 +147,15 @@ func handleStorageRequest(moduleName string, w http.ResponseWriter, r *http.Requ
switch xmlName {
case SakeNamespace + "/GetMyRecords":
response.Body.GetMyRecordsResponse = getMyRecords(moduleName, profileId, gameInfo, soap.Body.Data)
break
case SakeNamespace + "/UpdateRecord":
response.Body.UpdateRecordResponse = updateRecord(moduleName, profileId, gameInfo, soap.Body.Data)
break
case SakeNamespace + "/SearchForRecords":
response.Body.SearchForRecordsResponse = searchForRecords(moduleName, gameInfo, soap.Body.Data)
break
default:
logging.Error(moduleName, "Unknown SOAPAction:", aurora.Cyan(xmlName))
break
}
}
} else {
@ -190,7 +186,7 @@ func getRequestIdentity(moduleName string, request StorageRequestData) (uint32,
return 0, common.GameInfo{}, false
}
err, profileId, _ := common.UnmarshalGPCMLoginTicket(request.LoginTicket)
profileId, _, err := common.UnmarshalGPCMLoginTicket(request.LoginTicket)
if err != nil {
logging.Error(moduleName, err)
return 0, common.GameInfo{}, false
@ -237,7 +233,7 @@ func getMyRecords(moduleName string, profileId uint32, gameInfo common.GameInfo,
GetMyRecordsResult: "Error",
}
values := map[string]StorageValue{}
var values map[string]StorageValue
switch gameInfo.Name + "/" + request.TableID {
default:
@ -254,7 +250,6 @@ func getMyRecords(moduleName string, profileId uint32, gameInfo common.GameInfo,
"recordid": intValue(int32(profileId)),
"info": binaryDataValueBase64(database.GetMKWFriendInfo(pool, ctx, profileId)),
}
break
}
response := StorageGetMyRecordsResponse{
@ -299,7 +294,6 @@ func updateRecord(moduleName string, profileId uint32, gameInfo common.GameInfo,
// TODO: Validate record data
database.UpdateMKWFriendInfo(pool, ctx, profileId, request.Values.RecordFields[0].Value.Value.Value)
logging.Notice(moduleName, "Updated Mario Kart Wii friend info")
break
}
return &StorageUpdateRecordResponse{
@ -343,14 +337,13 @@ func searchForRecords(moduleName string, gameInfo common.GameInfo, request Stora
"info": binaryDataValueBase64(database.GetMKWFriendInfo(pool, ctx, uint32(ownerId))),
},
}
break
}
// Sort the values now
sort.Slice(values, func(l, r int) bool {
lVal, lExists := values[l][request.Sort]
rVal, rExists := values[r][request.Sort]
if lExists == false || rExists == false {
if !lExists || !rExists {
// Prioritises the one that exists or goes left if both false
return rExists
}