diff --git a/api/groups.go b/api/groups.go index 54b2f09..bc7e333 100644 --- a/api/groups.go +++ b/api/groups.go @@ -24,13 +24,14 @@ func HandleGroups(w http.ResponseWriter, r *http.Request) { return } - gameName := query.Get("gamename") + gameName := query.Get("game") groups := qr2.GetGroups(gameName) for _, group := range groups { for i, player := range group.Players { filtered := map[string]string{} + filtered["count"] = player["+localplayers"] filtered["pid"] = player["dwc_pid"] filtered["name"] = player["+ingamesn"] diff --git a/common/match_command.go b/common/match_command.go index c17e295..18d24cc 100644 --- a/common/match_command.go +++ b/common/match_command.go @@ -3,8 +3,9 @@ package common import ( "encoding/binary" "fmt" - "github.com/logrusorgru/aurora/v3" "wwfc/logging" + + "github.com/logrusorgru/aurora/v3" ) const ( @@ -39,6 +40,9 @@ const ( ) type MatchCommandData struct { + Version int + Command byte + Reservation *MatchCommandDataReservation ResvOK *MatchCommandDataResvOK ResvDeny *MatchCommandDataResvDeny @@ -199,10 +203,14 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD } if version == 3 && len(buffer) < 0x0C { - return MatchCommandData{Reservation: &MatchCommandDataReservation{ - MatchType: byte(matchType), - HasPublicIP: false, - }}, true + return MatchCommandData{ + Version: version, + Command: command, + Reservation: &MatchCommandDataReservation{ + MatchType: byte(matchType), + HasPublicIP: false, + }, + }, true } publicPort := binary.LittleEndian.Uint32(buffer[0x08:0x0C]) @@ -212,13 +220,17 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD switch version { case 3: - return MatchCommandData{Reservation: &MatchCommandDataReservation{ - MatchType: byte(matchType), - HasPublicIP: true, - PublicIP: binary.BigEndian.Uint32(buffer[0x04:0x08]), - PublicPort: uint16(publicPort), - UserData: buffer[0x0C:], - }}, true + return MatchCommandData{ + Version: version, + Command: command, + Reservation: &MatchCommandDataReservation{ + MatchType: byte(matchType), + HasPublicIP: true, + PublicIP: binary.BigEndian.Uint32(buffer[0x04:0x08]), + PublicPort: uint16(publicPort), + UserData: buffer[0x0C:], + }, + }, true case 11: isFriendValue := binary.LittleEndian.Uint32(buffer[0x0C:0x10]) @@ -227,15 +239,19 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD } isFriend := isFriendValue != 0 - return MatchCommandData{Reservation: &MatchCommandDataReservation{ - MatchType: byte(matchType), - HasPublicIP: true, - PublicIP: binary.BigEndian.Uint32(buffer[0x04:0x08]), - PublicPort: uint16(publicPort), - IsFriend: isFriend, - LocalPlayerCount: binary.LittleEndian.Uint32(buffer[0x10:0x14]), - UserData: buffer[0x14:], - }}, true + return MatchCommandData{ + Version: version, + Command: command, + Reservation: &MatchCommandDataReservation{ + MatchType: byte(matchType), + HasPublicIP: true, + PublicIP: binary.BigEndian.Uint32(buffer[0x04:0x08]), + PublicPort: uint16(publicPort), + IsFriend: isFriend, + LocalPlayerCount: binary.LittleEndian.Uint32(buffer[0x10:0x14]), + UserData: buffer[0x14:], + }, + }, true case 90: localPort := binary.LittleEndian.Uint32(buffer[0x10:0x14]) @@ -249,19 +265,22 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD } isFriend := isFriendValue != 0 - return MatchCommandData{Reservation: &MatchCommandDataReservation{ - MatchType: byte(matchType), - HasPublicIP: true, - PublicIP: binary.BigEndian.Uint32(buffer[0x04:0x08]), - PublicPort: uint16(publicPort), - LocalIP: binary.BigEndian.Uint32(buffer[0x0C:0x10]), - LocalPort: uint16(localPort), - Unknown: binary.LittleEndian.Uint32(buffer[0x14:0x18]), - IsFriend: isFriend, - LocalPlayerCount: binary.LittleEndian.Uint32(buffer[0x1C:0x20]), - ResvCheckValue: binary.LittleEndian.Uint32(buffer[0x20:0x24]), - UserData: buffer[0x24:], - }}, true + return MatchCommandData{ + Version: version, + Command: command, + Reservation: &MatchCommandDataReservation{ + MatchType: byte(matchType), + HasPublicIP: true, + PublicIP: binary.BigEndian.Uint32(buffer[0x04:0x08]), + PublicPort: uint16(publicPort), + LocalIP: binary.BigEndian.Uint32(buffer[0x0C:0x10]), + LocalPort: uint16(localPort), + Unknown: binary.LittleEndian.Uint32(buffer[0x14:0x18]), + IsFriend: isFriend, + LocalPlayerCount: binary.LittleEndian.Uint32(buffer[0x1C:0x20]), + ResvCheckValue: binary.LittleEndian.Uint32(buffer[0x20:0x24]), + UserData: buffer[0x24:], + }}, true } case MatchResvOK: @@ -291,13 +310,17 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD } if version == 3 { - return MatchCommandData{ResvOK: &MatchCommandDataResvOK{ - PublicIP: binary.BigEndian.Uint32(buffer[index : index+0x04]), - PublicPort: uint16(publicPort), - ClientCount: clientCount, - ProfileIDs: profileIDs, - UserData: buffer[index+0x8:], - }}, true + return MatchCommandData{ + Version: version, + Command: command, + ResvOK: &MatchCommandDataResvOK{ + PublicIP: binary.BigEndian.Uint32(buffer[index : index+0x04]), + PublicPort: uint16(publicPort), + ClientCount: clientCount, + ProfileIDs: profileIDs, + UserData: buffer[index+0x8:], + }, + }, true } else if version == 11 { isFriendValue := binary.LittleEndian.Uint32(buffer[index+0x08 : index+0x0C]) if isFriendValue > 1 { @@ -305,17 +328,20 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD } isFriend := isFriendValue != 0 - return MatchCommandData{ResvOK: &MatchCommandDataResvOK{ - MaxPlayers: binary.LittleEndian.Uint32(buffer[index+0x14 : index+0x18]), - SenderAID: binary.LittleEndian.Uint32(buffer[index+0x0C : index+0x10]), - PublicIP: binary.BigEndian.Uint32(buffer[index : index+0x04]), - PublicPort: uint16(publicPort), - GroupID: binary.LittleEndian.Uint32(buffer[index+0x10 : index+0x14]), - ClientCount: clientCount, - ProfileIDs: profileIDs, - IsFriend: isFriend, - UserData: buffer[index+0x18:], - }}, true + return MatchCommandData{ + Version: version, + Command: command, + ResvOK: &MatchCommandDataResvOK{ + MaxPlayers: binary.LittleEndian.Uint32(buffer[index+0x14 : index+0x18]), + SenderAID: binary.LittleEndian.Uint32(buffer[index+0x0C : index+0x10]), + PublicIP: binary.BigEndian.Uint32(buffer[index : index+0x04]), + PublicPort: uint16(publicPort), + GroupID: binary.LittleEndian.Uint32(buffer[index+0x10 : index+0x14]), + ClientCount: clientCount, + ProfileIDs: profileIDs, + IsFriend: isFriend, + UserData: buffer[index+0x18:], + }}, true } break } @@ -335,22 +361,26 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD break } - return MatchCommandData{ResvOK: &MatchCommandDataResvOK{ - MaxPlayers: binary.LittleEndian.Uint32(buffer[0x00:0x04]), - SenderAID: binary.LittleEndian.Uint32(buffer[0x04:0x08]), - ProfileID: binary.LittleEndian.Uint32(buffer[0x08:0x0C]), - PublicIP: binary.BigEndian.Uint32(buffer[0x0C:0x10]), - PublicPort: uint16(publicPort), - LocalIP: binary.BigEndian.Uint32(buffer[0x14:0x18]), - LocalPort: uint16(localPort), - Unknown: binary.LittleEndian.Uint32(buffer[0x1C:0x20]), - LocalPlayerCount: binary.LittleEndian.Uint32(buffer[0x20:0x24]), - GroupID: binary.LittleEndian.Uint32(buffer[0x24:0x28]), - ReceiverNewAID: binary.LittleEndian.Uint32(buffer[0x28:0x2C]), - ClientCount: binary.LittleEndian.Uint32(buffer[0x2C:0x30]), - ResvCheckValue: binary.LittleEndian.Uint32(buffer[0x30:0x34]), - UserData: buffer[0x34:], - }}, true + return MatchCommandData{ + Version: version, + Command: command, + ResvOK: &MatchCommandDataResvOK{ + MaxPlayers: binary.LittleEndian.Uint32(buffer[0x00:0x04]), + SenderAID: binary.LittleEndian.Uint32(buffer[0x04:0x08]), + ProfileID: binary.LittleEndian.Uint32(buffer[0x08:0x0C]), + PublicIP: binary.BigEndian.Uint32(buffer[0x0C:0x10]), + PublicPort: uint16(publicPort), + LocalIP: binary.BigEndian.Uint32(buffer[0x14:0x18]), + LocalPort: uint16(localPort), + Unknown: binary.LittleEndian.Uint32(buffer[0x1C:0x20]), + LocalPlayerCount: binary.LittleEndian.Uint32(buffer[0x20:0x24]), + GroupID: binary.LittleEndian.Uint32(buffer[0x24:0x28]), + ReceiverNewAID: binary.LittleEndian.Uint32(buffer[0x28:0x2C]), + ClientCount: binary.LittleEndian.Uint32(buffer[0x2C:0x30]), + ResvCheckValue: binary.LittleEndian.Uint32(buffer[0x30:0x34]), + UserData: buffer[0x34:], + }, + }, true case MatchResvDeny: if len(buffer) != 0x04 { @@ -371,11 +401,15 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD break } - return MatchCommandData{ResvDeny: &MatchCommandDataResvDeny{ - Reason: reason, - ReasonString: reasonString, - UserData: buffer[0x4:], - }}, true + return MatchCommandData{ + Version: version, + Command: command, + ResvDeny: &MatchCommandDataResvDeny{ + Reason: reason, + ReasonString: reasonString, + UserData: buffer[0x4:], + }, + }, true case MatchResvWait: if len(buffer) != 0x00 { @@ -399,10 +433,14 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD break } - return MatchCommandData{TellAddr: &MatchCommandDataTellAddr{ - LocalIP: binary.BigEndian.Uint32(buffer[0x00:0x04]), - LocalPort: uint16(localPort), - }}, true + return MatchCommandData{ + Version: version, + Command: command, + TellAddr: &MatchCommandDataTellAddr{ + LocalIP: binary.BigEndian.Uint32(buffer[0x00:0x04]), + LocalPort: uint16(localPort), + }, + }, true case MatchServerCloseClient: // Max match command buffer size for QR2/GT2 @@ -421,32 +459,46 @@ func DecodeMatchCommand(command byte, buffer []byte, version int) (MatchCommandD pids = append(pids, binary.LittleEndian.Uint32(buffer[i*4:i*4+4])) } - return MatchCommandData{ServerCloseClient: &MatchCommandDataServerCloseClient{ - ProfileIDs: pids, - }}, true + return MatchCommandData{ + Version: version, + Command: command, + ServerCloseClient: &MatchCommandDataServerCloseClient{ + ProfileIDs: pids, + }, + }, true case MatchSuspendMatch: if len(buffer) == 0x08 { - return MatchCommandData{SuspendMatch: &MatchCommandDataSuspendMatch{ - HostProfileID: binary.LittleEndian.Uint32(buffer[0x00:0x04]), - IsHostFlag: binary.LittleEndian.Uint32(buffer[0x04:0x08]), - Short: true, - }}, true + return MatchCommandData{ + Version: version, + Command: command, + SuspendMatch: &MatchCommandDataSuspendMatch{ + HostProfileID: binary.LittleEndian.Uint32(buffer[0x00:0x04]), + IsHostFlag: binary.LittleEndian.Uint32(buffer[0x04:0x08]), + Short: true, + }, + }, true } else if len(buffer) == 0x10 { - return MatchCommandData{SuspendMatch: &MatchCommandDataSuspendMatch{ - HostProfileID: binary.LittleEndian.Uint32(buffer[0x00:0x04]), - IsHostFlag: binary.LittleEndian.Uint32(buffer[0x04:0x08]), - Short: false, - SuspendValue: binary.LittleEndian.Uint32(buffer[0x08:0x0C]), - ClientAIDValue: binary.LittleEndian.Uint32(buffer[0x0C:0x10]), - }}, true + return MatchCommandData{ + Version: version, + Command: command, + SuspendMatch: &MatchCommandDataSuspendMatch{ + HostProfileID: binary.LittleEndian.Uint32(buffer[0x00:0x04]), + IsHostFlag: binary.LittleEndian.Uint32(buffer[0x04:0x08]), + Short: false, + SuspendValue: binary.LittleEndian.Uint32(buffer[0x08:0x0C]), + ClientAIDValue: binary.LittleEndian.Uint32(buffer[0x0C:0x10]), + }, + }, true } } return MatchCommandData{}, false } -func EncodeMatchCommand(command byte, data MatchCommandData, version int) ([]byte, bool) { +func EncodeMatchCommand(command byte, data MatchCommandData) ([]byte, bool) { + version := data.Version + if version != 3 && version != 11 && version != 90 { return []byte{}, false } diff --git a/gpcm/friend.go b/gpcm/friend.go index 16c1c03..a46e7c9 100644 --- a/gpcm/friend.go +++ b/gpcm/friend.go @@ -417,12 +417,18 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) { 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 { + if toSession.ReservationPID != g.User.ProfileId || g.Reservation.Reservation == nil { logging.Error(g.ModuleName, "Destination", aurora.Cyan(toProfileId), "has no reservation with the sender") g.replyError(ErrMessage) return } + if g.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") @@ -430,7 +436,7 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) { return } - if !qr2.ProcessGPResvOK(*msgMatchData.ResvOK, g.QR2IP, g.User.ProfileId, toSession.QR2IP, uint32(toProfileId)) { + if !qr2.ProcessGPResvOK(msgMatchData.Version, *g.Reservation.Reservation, *msgMatchData.ResvOK, g.QR2IP, g.User.ProfileId, toSession.QR2IP, uint32(toProfileId)) { g.replyError(ErrMessage) return } @@ -449,7 +455,7 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) { } } - newMsg, ok := common.EncodeMatchCommand(cmd, msgMatchData, version) + newMsg, ok := common.EncodeMatchCommand(cmd, msgMatchData) if !ok || len(newMsg) > 0x200 { logging.Error(g.ModuleName, "Failed to encode match command; message:", msg) g.replyError(ErrMessage) @@ -457,6 +463,7 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) { } if cmd == common.MatchReservation { + g.Reservation = msgMatchData g.ReservationPID = uint32(toProfileId) } diff --git a/gpcm/main.go b/gpcm/main.go index 95788cb..41329ca 100644 --- a/gpcm/main.go +++ b/gpcm/main.go @@ -35,6 +35,7 @@ type GameSpySession struct { AuthFriendList []uint32 QR2IP uint64 + Reservation common.MatchCommandData ReservationPID uint32 NeedsExploit bool diff --git a/qr2/group.go b/qr2/group.go index dfee994..be1e8bc 100644 --- a/qr2/group.go +++ b/qr2/group.go @@ -11,18 +11,19 @@ import ( ) type Group struct { - GroupID uint32 - GroupName string - GameName string - MatchType string - MKWRegion string - Server *Session - Players map[*Session]bool + GroupID uint32 + GroupName string + GameName string + MatchType string + MKWRegion string + LastJoinIndex int + Server *Session + Players map[*Session]bool } var groups = map[string]*Group{} -func processResvOK(moduleName string, cmd common.MatchCommandDataResvOK, sender, destination *Session) bool { +func processResvOK(moduleName string, matchVersion int, reservation common.MatchCommandDataReservation, resvOK common.MatchCommandDataResvOK, sender, destination *Session) bool { if len(groups) >= 100000 { logging.Error(moduleName, "Hit arbitrary global maximum group count (somehow)") return false @@ -31,13 +32,14 @@ func processResvOK(moduleName string, cmd common.MatchCommandDataResvOK, sender, group := sender.GroupPointer if group == nil { group = &Group{ - GroupID: cmd.GroupID, - GroupName: "", - GameName: sender.Data["gamename"], - MatchType: sender.Data["dwc_mtype"], - MKWRegion: "", - Server: sender, - Players: map[*Session]bool{sender: true}, + GroupID: resvOK.GroupID, + GroupName: "", + GameName: sender.Data["gamename"], + MatchType: sender.Data["dwc_mtype"], + MKWRegion: "", + LastJoinIndex: 0, + Server: sender, + Players: map[*Session]bool{sender: true}, } for { @@ -62,6 +64,11 @@ func processResvOK(moduleName string, cmd common.MatchCommandDataResvOK, sender, group.MKWRegion = rk } + sender.Data["+joinindex"] = "0" + if matchVersion == 90 { + sender.Data["+localplayers"] = strconv.FormatUint(uint64(resvOK.LocalPlayerCount), 10) + } + sender.GroupPointer = group groups[group.GroupName] = group @@ -71,16 +78,23 @@ func processResvOK(moduleName string, cmd common.MatchCommandDataResvOK, sender, // TODO: Check if the sender is the actual server (host) once host migration works // Keep group ID updated - sender.GroupPointer.GroupID = cmd.GroupID + group.GroupID = resvOK.GroupID logging.Info(moduleName, "New player", aurora.BrightCyan(destination.Data["dwc_pid"]), "in group", aurora.Cyan(group.GroupName)) + + group.LastJoinIndex++ + destination.Data["+joinindex"] = strconv.Itoa(group.LastJoinIndex) + if matchVersion == 90 { + destination.Data["+localplayers"] = strconv.FormatUint(uint64(reservation.LocalPlayerCount), 10) + } + group.Players[destination] = true destination.GroupPointer = group return true } -func ProcessGPResvOK(cmd common.MatchCommandDataResvOK, senderIP uint64, senderPid uint32, destIP uint64, destPid uint32) bool { +func ProcessGPResvOK(matchVersion int, reservation common.MatchCommandDataReservation, resvOK common.MatchCommandDataResvOK, senderIP uint64, senderPid uint32, destIP uint64, destPid uint32) bool { senderPidStr := strconv.FormatUint(uint64(senderPid), 10) destPidStr := strconv.FormatUint(uint64(destPid), 10) @@ -110,7 +124,7 @@ func ProcessGPResvOK(cmd common.MatchCommandDataResvOK, senderIP uint64, senderP return false } - return processResvOK(moduleName, cmd, from, to) + return processResvOK(moduleName, matchVersion, reservation, resvOK, from, to) } func ProcessGPStatusUpdate(profileID uint32, senderIP uint64, status string) { @@ -176,13 +190,13 @@ func ProcessGPStatusUpdate(profileID uint32, senderIP uint64, status string) { } type GroupInfo struct { - GroupName string `json:"id"` - GameName string `json:"gamename"` - MatchType string `json:"type"` - Suspend bool `json:"suspend"` - ServerPID string `json:"host,omitempty"` - MKWRegion string `json:"rk,omitempty"` - Players []map[string]string `json:"players"` + GroupName string `json:"id"` + GameName string `json:"game"` + MatchType string `json:"type"` + Suspend bool `json:"suspend"` + ServerIndex string `json:"host,omitempty"` + MKWRegion string `json:"rk,omitempty"` + Players map[string]map[string]string `json:"players"` } // GetGroups returns an unsorted copy of all online rooms @@ -196,12 +210,12 @@ func GetGroups(gameName string) []GroupInfo { } groupInfo := GroupInfo{ - GroupName: group.GroupName, - GameName: group.GameName, - Suspend: true, - ServerPID: "", - MKWRegion: "", - Players: []map[string]string{}, + GroupName: group.GroupName, + GameName: group.GameName, + Suspend: true, + ServerIndex: "", + MKWRegion: "", + Players: map[string]map[string]string{}, } if group.MatchType == "0" || group.MatchType == "1" { @@ -213,7 +227,7 @@ func GetGroups(gameName string) []GroupInfo { } if groupInfo.MatchType == "private" && group.Server != nil { - groupInfo.ServerPID = group.Server.Data["dwc_pid"] + groupInfo.ServerIndex = group.Server.Data["+joinindex"] } if groupInfo.GameName == "mariokartwii" { @@ -228,7 +242,7 @@ func GetGroups(gameName string) []GroupInfo { mapData["+ingamesn"] = session.Login.InGameName - groupInfo.Players = append(groupInfo.Players, mapData) + groupInfo.Players[mapData["+joinindex"]] = mapData if mapData["dwc_hoststate"] == "2" && mapData["dwc_suspend"] == "0" { groupInfo.Suspend = false diff --git a/qr2/message.go b/qr2/message.go index c8d2807..4550a76 100644 --- a/qr2/message.go +++ b/qr2/message.go @@ -112,6 +112,14 @@ func SendClientMessage(senderIP string, destSearchID uint64, message []byte) { return } + mutex.Lock() + if sender.Data["gamename"] != receiver.Data["gamename"] { + mutex.Unlock() + logging.Error(moduleName, "Sender and receiver are not playing the same game") + return + } + mutex.Unlock() + var ok bool matchData, ok = common.DecodeMatchCommand(message[8], message[0x14:], version) if !ok { @@ -209,7 +217,7 @@ func SendClientMessage(senderIP string, destSearchID uint64, message []byte) { } var matchMessage []byte - matchMessage, ok = common.EncodeMatchCommand(message[8], matchData, version) + matchMessage, ok = common.EncodeMatchCommand(message[8], matchData) if !ok || len(matchMessage) > 0x80 { logging.Error(moduleName, "Failed to reencode match command:", aurora.Cyan(printHex(message))) return @@ -223,6 +231,7 @@ func SendClientMessage(senderIP string, destSearchID uint64, message []byte) { } mutex.Lock() + defer mutex.Unlock() destPid, ok := receiver.Data["dwc_pid"] if !ok || destPid == "" { @@ -234,8 +243,6 @@ func SendClientMessage(senderIP string, destSearchID uint64, message []byte) { receiver.PacketCount = packetCount destAddr := receiver.Addr - mutex.Unlock() - if isNatnegPacket { cookie := binary.BigEndian.Uint32(message[0x2:0x6]) logging.Notice(moduleName, "Send NN cookie", aurora.Cyan(cookie), "to", aurora.BrightCyan(destPid)) @@ -244,20 +251,25 @@ func SendClientMessage(senderIP string, destSearchID uint64, message []byte) { common.LogMatchCommand(moduleName, destPid, cmd, matchData) if cmd == common.MatchReservation { + sender.Reservation = matchData sender.ReservationID = receiver.SearchID } else if cmd == common.MatchResvOK || cmd == common.MatchResvDeny || cmd == common.MatchResvWait { - if receiver.ReservationID != sender.SearchID { + if receiver.ReservationID != sender.SearchID || receiver.Reservation.Reservation == nil { logging.Error(moduleName, "Destination has no reservation with the sender") return } + if receiver.Reservation.Version != matchData.Version { + logging.Error(moduleName, "Reservation version mismatch") + return + } + if cmd == common.MatchResvOK { - mutex.Lock() - if !processResvOK(moduleName, *matchData.ResvOK, sender, receiver) { - mutex.Unlock() + if !processResvOK(moduleName, matchData.Version, *receiver.Reservation.Reservation, *matchData.ResvOK, sender, receiver) { return } - mutex.Unlock() + } else { + receiver.ReservationID = 0 } } } diff --git a/qr2/session.go b/qr2/session.go index c09992a..b47ee3d 100644 --- a/qr2/session.go +++ b/qr2/session.go @@ -32,6 +32,7 @@ type Session struct { Data map[string]string PacketCount uint32 ReservationID uint64 + Reservation common.MatchCommandData GroupPointer *Group } @@ -101,6 +102,7 @@ func setSessionData(moduleName string, addr net.Addr, sessionId uint32, payload Endianness: ClientNoEndian, Data: payload, PacketCount: 0, + Reservation: common.MatchCommandData{}, ReservationID: 0, } }