Rename gcsp to gpsp, master to qr2

This commit is contained in:
mkwcat
2023-10-24 22:26:35 -04:00
parent c9b9835364
commit eca4f7f0ed
9 changed files with 173 additions and 226 deletions

View File

@@ -1,193 +0,0 @@
package gcsp
import (
"bufio"
"context"
"errors"
"fmt"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/logrusorgru/aurora/v3"
"io"
"net"
"strconv"
"strings"
"time"
"wwfc/common"
"wwfc/database"
"wwfc/logging"
)
var (
ctx = context.Background()
pool *pgxpool.Pool
userId int64
)
func StartServer() {
// Get config
config := common.GetConfig()
// Start SQL
dbString := fmt.Sprintf("postgres://%s:%s@%s/%s", config.Username, config.Password, config.DatabaseAddress, config.DatabaseName)
dbConf, err := pgxpool.ParseConfig(dbString)
if err != nil {
panic(err)
}
pool, err = pgxpool.ConnectConfig(ctx, dbConf)
if err != nil {
panic(err)
}
address := config.Address + ":29901"
l, err := net.Listen("tcp", address)
if err != nil {
panic(err)
}
// Close the listener when the application closes.
defer l.Close()
logging.Notice("GCSP", "Listening on", address)
for {
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
panic(err)
}
// Handle connections in a new goroutine.
go handleRequest(conn)
}
}
// Handles incoming requests.
func handleRequest(conn net.Conn) {
defer conn.Close()
moduleName := "GCSP"
knownProfileId := uint32(0)
err := conn.(*net.TCPConn).SetKeepAlive(true)
if err != nil {
logging.Notice(moduleName, "Unable to set keepalive:", err.Error())
}
err = conn.(*net.TCPConn).SetKeepAlivePeriod(time.Hour * 1000)
if err != nil {
logging.Notice(moduleName, "Unable to set keepalive:", err.Error())
}
logging.Notice(moduleName, "Connection established from", conn.RemoteAddr().String())
// Here we go into the listening loop
for {
buffer := make([]byte, 1024)
_, err := bufio.NewReader(conn).Read(buffer)
if err != nil {
if errors.Is(err, io.EOF) {
// Client closed connection, terminate.
return
}
}
commands, err := common.ParseGameSpyMessage(string(buffer))
if err != nil {
panic(err)
}
for _, command := range commands {
logging.Notice(moduleName, "Command:", aurora.Yellow(command.Command).String())
switch command.Command {
case "ka":
conn.Write([]byte(`\ka\\final\`))
break
case "otherslist":
strProfileId, ok := command.OtherValues["profileid"]
if !ok {
logging.Notice(moduleName, "Missing profileid in otherslist")
return
}
profileId, err := strconv.ParseUint(strProfileId, 10, 32)
if err != nil {
panic(err)
}
if knownProfileId == 0 {
knownProfileId = uint32(profileId)
moduleName = "GCSP:" + strconv.FormatUint(profileId, 10)
moduleName += "/" + common.CalcFriendCodeString(uint32(profileId), "RMCJ")
} else if uint32(profileId) != knownProfileId {
logging.Notice(moduleName, "WARN: Mismatched profile ID in otherslist:", aurora.Cyan(strProfileId).String())
}
conn.Write([]byte(handleOthersList(moduleName, uint32(profileId), command)))
break
}
}
}
}
func handleOthersList(moduleName string, profileId uint32, command common.GameSpyCommand) string {
empty := `\otherslist\\final\`
_, ok := command.OtherValues["sesskey"]
if !ok {
logging.Notice(moduleName, "Missing sesskey in otherslist")
return empty
}
numopids, ok := command.OtherValues["numopids"]
if !ok {
logging.Notice(moduleName, "Missing numopids in otherslist")
return empty
}
opids, ok := command.OtherValues["opids"]
if !ok {
logging.Notice(moduleName, "Missing opids in otherslist")
return empty
}
_, ok = command.OtherValues["gamename"]
if !ok {
logging.Notice(moduleName, "Missing gamename in otherslist")
return empty
}
numOpidsValue, err := strconv.Atoi(numopids)
if err != nil {
panic(err)
}
opidsSplit := strings.Split(opids, "|")
if len(opidsSplit) != numOpidsValue {
logging.Notice(moduleName, "Mismatch opids length with numopids:", aurora.Cyan(len(opidsSplit)).String(), "!=", aurora.Cyan(numOpidsValue).String())
return empty
}
payload := `\otherslist\`
for _, strOtherId := range opidsSplit {
otherId, err := strconv.ParseUint(strOtherId, 10, 32)
if err != nil {
panic(err)
}
// TODO: Perhaps this could be condensed into one database query
// Also TODO: Check if the players are actually friends
user, ok := database.GetProfile(pool, ctx, uint32(otherId))
if !ok {
logging.Notice(moduleName, "Other ID doesn't exist:", aurora.Cyan(strOtherId).String())
// If the profile doesn't exist then skip adding it
continue
}
payload += `\o\` + strconv.FormatUint(uint64(user.ProfileId), 10)
payload += `\uniquenick\` + user.UniqueNick
}
payload += `\oldone\\final\`
return payload
}

View File

@@ -1,18 +1,45 @@
package gpsp
import (
"bufio"
"context"
"errors"
"fmt"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/logrusorgru/aurora/v3"
"io"
"net"
"os"
"strconv"
"strings"
"time"
"wwfc/common"
"wwfc/database"
"wwfc/logging"
)
var (
ctx = context.Background()
pool *pgxpool.Pool
userId int64
)
func StartServer() {
// Get config
config := common.GetConfig()
address := config.Address + ":27900"
// Start SQL
dbString := fmt.Sprintf("postgres://%s:%s@%s/%s", config.Username, config.Password, config.DatabaseAddress, config.DatabaseName)
dbConf, err := pgxpool.ParseConfig(dbString)
if err != nil {
panic(err)
}
pool, err = pgxpool.ConnectConfig(ctx, dbConf)
if err != nil {
panic(err)
}
address := config.Address + ":29901"
l, err := net.Listen("tcp", address)
if err != nil {
panic(err)
@@ -36,16 +63,131 @@ func StartServer() {
// Handles incoming requests.
func handleRequest(conn net.Conn) {
// Make a buffer to hold incoming data.
buf := make([]byte, 1024)
// Read the incoming connection into the buffer.
reqLen, err := conn.Read(buf)
defer conn.Close()
moduleName := "GPSP"
knownProfileId := uint32(0)
err := conn.(*net.TCPConn).SetKeepAlive(true)
if err != nil {
logging.Notice(moduleName, "Unable to set keepalive:", err.Error())
}
err = conn.(*net.TCPConn).SetKeepAlivePeriod(time.Hour * 1000)
if err != nil {
logging.Notice(moduleName, "Unable to set keepalive:", err.Error())
}
logging.Notice(moduleName, "Connection established from", conn.RemoteAddr().String())
// Here we go into the listening loop
for {
buffer := make([]byte, 1024)
_, err := bufio.NewReader(conn).Read(buffer)
if err != nil {
if errors.Is(err, io.EOF) {
// Client closed connection, terminate.
return
}
}
commands, err := common.ParseGameSpyMessage(string(buffer))
if err != nil {
panic(err)
}
for _, command := range commands {
logging.Notice(moduleName, "Command:", aurora.Yellow(command.Command).String())
switch command.Command {
case "ka":
conn.Write([]byte(`\ka\\final\`))
break
case "otherslist":
strProfileId, ok := command.OtherValues["profileid"]
if !ok {
logging.Notice(moduleName, "Missing profileid in otherslist")
return
}
profileId, err := strconv.ParseUint(strProfileId, 10, 32)
if err != nil {
panic(err)
}
if knownProfileId == 0 {
knownProfileId = uint32(profileId)
moduleName = "GPSP:" + strconv.FormatUint(profileId, 10)
moduleName += "/" + common.CalcFriendCodeString(uint32(profileId), "RMCJ")
} else if uint32(profileId) != knownProfileId {
logging.Notice(moduleName, "WARN: Mismatched profile ID in otherslist:", aurora.Cyan(strProfileId).String())
}
conn.Write([]byte(handleOthersList(moduleName, uint32(profileId), command)))
break
}
}
}
}
func handleOthersList(moduleName string, profileId uint32, command common.GameSpyCommand) string {
empty := `\otherslist\\final\`
_, ok := command.OtherValues["sesskey"]
if !ok {
logging.Notice(moduleName, "Missing sesskey in otherslist")
return empty
}
numopids, ok := command.OtherValues["numopids"]
if !ok {
logging.Notice(moduleName, "Missing numopids in otherslist")
return empty
}
opids, ok := command.OtherValues["opids"]
if !ok {
logging.Notice(moduleName, "Missing opids in otherslist")
return empty
}
_, ok = command.OtherValues["gamename"]
if !ok {
logging.Notice(moduleName, "Missing gamename in otherslist")
return empty
}
numOpidsValue, err := strconv.Atoi(numopids)
if err != nil {
panic(err)
}
// Send a response back to person contacting us.
conn.Write([]byte(`\ka\\final\`))
// Close the connection when you're done with it.
conn.Close()
opidsSplit := strings.Split(opids, "|")
if len(opidsSplit) != numOpidsValue {
logging.Notice(moduleName, "Mismatch opids length with numopids:", aurora.Cyan(len(opidsSplit)).String(), "!=", aurora.Cyan(numOpidsValue).String())
return empty
}
payload := `\otherslist\`
for _, strOtherId := range opidsSplit {
otherId, err := strconv.ParseUint(strOtherId, 10, 32)
if err != nil {
panic(err)
}
// TODO: Perhaps this could be condensed into one database query
// Also TODO: Check if the players are actually friends
user, ok := database.GetProfile(pool, ctx, uint32(otherId))
if !ok {
logging.Notice(moduleName, "Other ID doesn't exist:", aurora.Cyan(strOtherId).String())
// If the profile doesn't exist then skip adding it
continue
}
payload += `\o\` + strconv.FormatUint(uint64(user.ProfileId), 10)
payload += `\uniquenick\` + user.UniqueNick
}
payload += `\oldone\\final\`
return payload
}

View File

@@ -2,16 +2,16 @@ package main
import (
"sync"
"wwfc/gcsp"
"wwfc/gpcm"
"wwfc/master"
"wwfc/gpsp"
"wwfc/matchmaking"
"wwfc/nas"
"wwfc/qr2"
)
func main() {
wg := &sync.WaitGroup{}
actions := []func(){nas.StartServer, gpcm.StartServer, master.StartServer, gcsp.StartServer, matchmaking.StartServer}
actions := []func(){nas.StartServer, gpcm.StartServer, qr2.StartServer, gpsp.StartServer, matchmaking.StartServer}
wg.Add(5)
for _, action := range actions {
go func(ac func()) {

View File

@@ -23,7 +23,7 @@ var (
)
const (
ModuleName = "MATCHMAKING"
ModuleName = "SB"
// Requests sent from the client
ServerListRequest = 0x00
@@ -66,7 +66,7 @@ func StartServer() {
// Close the listener when the application closes.
defer l.Close()
logging.Notice("MATCHMAKING", "Listening on", address)
logging.Notice(ModuleName, "Listening on", address)
for {
// Listen for an incoming connection.
@@ -105,10 +105,11 @@ func handleRequest(conn net.Conn) {
bufferSize -= int(packetSize)
packetSize = 0
// Packets tend to be sent in fragments, so this loop makes sure the packets has been fully received before continuing
for {
if bufferSize > 2 {
packetSize = binary.BigEndian.Uint16(buffer[:2])
if packetSize < 3 {
if packetSize < 3 || packetSize >= 1024 {
logging.Notice(ModuleName, "Invalid packet size - terminating")
return
}
@@ -133,9 +134,6 @@ func handleRequest(conn net.Conn) {
bufferSize += readSize
}
logging.Notice(ModuleName, "packet size:", aurora.Cyan(packetSize).String())
logging.Notice(ModuleName, "buffer size:", aurora.Cyan(bufferSize).String())
switch buffer[2] {
case ServerListRequest:
logging.Notice(ModuleName, "Command:", aurora.Yellow("SERVER_LIST_REQUEST").String())

View File

@@ -9,7 +9,7 @@ import (
"strings"
"wwfc/common"
"wwfc/logging"
"wwfc/master"
"wwfc/qr2"
)
const (
@@ -40,7 +40,7 @@ const (
func FindServers(gueryGame string, filter string) ([]map[string]string, error) {
// TODO: Handle gueryGame, filter
return master.GetSessionServers(), nil
return qr2.GetSessionServers(), nil
}
func popString(buffer []byte, index int) (string, int) {
@@ -249,5 +249,5 @@ func handleSendMessageRequest(conn net.Conn, buffer []byte) {
// TODO: Perform basic packet verification
// TODO SECURITY: Check if the selected IP is actually online, or at least make sure it's not a local IP
master.SendClientMessage(destIP, buffer[9:])
qr2.SendClientMessage(destIP, buffer[9:])
}

View File

@@ -1,4 +1,4 @@
package master
package qr2
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package master
package qr2
import (
"encoding/binary"
@@ -11,7 +11,7 @@ import (
func heartbeat(conn net.PacketConn, addr net.Addr, buffer []byte) {
sessionId := binary.BigEndian.Uint32(buffer[1:5])
moduleName := "MASTER:" + strconv.FormatInt(int64(sessionId), 10)
moduleName := "QR2:" + strconv.FormatInt(int64(sessionId), 10)
logging.Notice(moduleName, "Received heartbeat from", aurora.Cyan(addr).String())
values := strings.Split(string(buffer[5:]), "\u0000")

View File

@@ -1,4 +1,4 @@
package master
package qr2
import (
"encoding/binary"
@@ -46,7 +46,7 @@ func StartServer() {
// Close the listener when the application closes.
defer conn.Close()
logging.Notice("MASTER", "Listening on", address)
logging.Notice("QR2", "Listening on", address)
for {
buf := make([]byte, 1024)
@@ -61,13 +61,13 @@ func StartServer() {
func handleConnection(conn net.PacketConn, addr net.Addr, buffer []byte) {
if buffer[0] == AvailableRequest {
logging.Notice("MASTER", "Command:", aurora.Yellow("AVAILABLE").String())
logging.Notice("QR2", "Command:", aurora.Yellow("AVAILABLE").String())
conn.WriteTo(createResponseHeader(AvailableRequest, 0), addr)
return
}
sessionId := binary.BigEndian.Uint32(buffer[1:5])
moduleName := "MASTER:" + strconv.FormatInt(int64(sessionId), 10)
moduleName := "QR2:" + strconv.FormatInt(int64(sessionId), 10)
switch buffer[0] {
case QueryRequest:

View File

@@ -1,4 +1,4 @@
package master
package qr2
import (
"encoding/binary"
@@ -38,7 +38,7 @@ func setSessionData(sessionId uint32, payload map[string]string) Session {
session, exists := sessions[sessionId]
if !exists {
logging.Notice("MASTER", "Creating session", aurora.Cyan(sessionId).String())
logging.Notice("QR2", "Creating session", aurora.Cyan(sessionId).String())
data := Session{
SessionID: sessionId,
Challenge: "",
@@ -123,12 +123,12 @@ func SendClientMessage(destIP string, message []byte) {
panic(err)
}
logging.Notice("MASTER", "Sending message...")
logging.Notice("QR2", "Sending message...")
masterConn.WriteTo(payload, destIPAddr)
return
}
}
mutex.Unlock()
logging.Notice("MASTER", "Could not find destination server")
logging.Notice("QR2", "Could not find destination server")
}