mirror of
https://github.com/WiiLink24/wfc-server.git
synced 2026-07-26 13:10:51 -05:00
Base for sending messages between clients
This commit is contained in:
parent
b47fe639ae
commit
c9b9835364
|
|
@ -3,12 +3,11 @@ package database
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/logrusorgru/aurora/v3"
|
||||
"strconv"
|
||||
"wwfc/common"
|
||||
"wwfc/logging"
|
||||
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/logrusorgru/aurora/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ package database
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"wwfc/common"
|
||||
|
||||
"github.com/jackc/pgx/v4"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"math/rand"
|
||||
"wwfc/common"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -70,13 +69,14 @@ func deleteSession(pool *pgxpool.Pool, ctx context.Context, profileId uint32) {
|
|||
}
|
||||
}
|
||||
|
||||
func GetProfile(pool *pgxpool.Pool, ctx context.Context, profileId uint32) User {
|
||||
func GetProfile(pool *pgxpool.Pool, ctx context.Context, profileId uint32) (User, bool) {
|
||||
user := User{}
|
||||
row := pool.QueryRow(ctx, GetUser, profileId)
|
||||
err := row.Scan(&user.UserId, &user.GsbrCode, &user.Password, &user.Email, &user.UniqueNick, &user.FirstName, &user.LastName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return User{}, false
|
||||
}
|
||||
|
||||
return user
|
||||
user.ProfileId = profileId
|
||||
return user, true
|
||||
}
|
||||
|
|
|
|||
100
gcsp/main.go
100
gcsp/main.go
|
|
@ -9,8 +9,11 @@ import (
|
|||
"github.com/logrusorgru/aurora/v3"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"wwfc/common"
|
||||
"wwfc/database"
|
||||
"wwfc/logging"
|
||||
)
|
||||
|
||||
|
|
@ -62,17 +65,20 @@ func StartServer() {
|
|||
func handleRequest(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
moduleName := "GCSP"
|
||||
knownProfileId := uint32(0)
|
||||
|
||||
err := conn.(*net.TCPConn).SetKeepAlive(true)
|
||||
if err != nil {
|
||||
logging.Notice("GCSP", "Unable to set keepalive:", err.Error())
|
||||
logging.Notice(moduleName, "Unable to set keepalive:", err.Error())
|
||||
}
|
||||
|
||||
err = conn.(*net.TCPConn).SetKeepAlivePeriod(time.Hour * 1000)
|
||||
if err != nil {
|
||||
logging.Notice("GCSP", "Unable to set keepalive:", err.Error())
|
||||
logging.Notice(moduleName, "Unable to set keepalive:", err.Error())
|
||||
}
|
||||
|
||||
logging.Notice("GCSP", "Connection established from", conn.RemoteAddr().String())
|
||||
logging.Notice(moduleName, "Connection established from", conn.RemoteAddr().String())
|
||||
|
||||
// Here we go into the listening loop
|
||||
for {
|
||||
|
|
@ -91,17 +97,97 @@ func handleRequest(conn net.Conn) {
|
|||
}
|
||||
|
||||
for _, command := range commands {
|
||||
logging.Notice("GCSP", "Command:", aurora.Yellow(command.Command).String())
|
||||
logging.Notice(moduleName, "Command:", aurora.Yellow(command.Command).String())
|
||||
switch command.Command {
|
||||
case "ka":
|
||||
conn.Write([]byte(`\ka\\final\`))
|
||||
break
|
||||
|
||||
case "otherslist":
|
||||
// This message needs to be sorted so we can't use a regular map
|
||||
payload := `\otherslist\\oldone\\o\0\uniquenick\7me4ijr5sRMCJ3d9uhvh\final\`
|
||||
conn.Write([]byte(payload))
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,18 @@ func Login(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, com
|
|||
}
|
||||
session.User = user
|
||||
|
||||
// Check to see if a session is already open with this profile ID
|
||||
// TODO: Test this
|
||||
mutex.Lock()
|
||||
_, exists := sessions[session.User.ProfileId]
|
||||
if exists {
|
||||
mutex.Unlock()
|
||||
// TODO: Return an error
|
||||
log.Fatalf("Session with profile ID %u is already open", session.User.ProfileId)
|
||||
}
|
||||
sessions[session.User.ProfileId] = session
|
||||
mutex.Unlock()
|
||||
|
||||
loginTicket := strings.Replace(base64.StdEncoding.EncodeToString([]byte(common.RandomString(16))), "=", "_", -1)
|
||||
// Now initiate the session
|
||||
_ = database.CreateSession(pool, ctx, session.User.ProfileId, loginTicket)
|
||||
|
|
|
|||
37
gpcm/main.go
37
gpcm/main.go
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/logrusorgru/aurora/v3"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
"wwfc/common"
|
||||
"wwfc/database"
|
||||
|
|
@ -16,14 +17,19 @@ import (
|
|||
)
|
||||
|
||||
type GameSpySession struct {
|
||||
Conn net.Conn
|
||||
User database.User
|
||||
ModuleName string
|
||||
LoggedIn bool
|
||||
Status string
|
||||
}
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
pool *pgxpool.Pool
|
||||
// I would use a sync.Map instead of the map mutex combo, but this performs better.
|
||||
sessions = map[uint32]*GameSpySession{}
|
||||
mutex = sync.RWMutex{}
|
||||
)
|
||||
|
||||
func StartServer() {
|
||||
|
|
@ -64,15 +70,27 @@ func StartServer() {
|
|||
}
|
||||
}
|
||||
|
||||
func closeSession(session *GameSpySession) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
session.Conn.Close()
|
||||
if session.LoggedIn {
|
||||
delete(sessions, session.User.ProfileId)
|
||||
}
|
||||
}
|
||||
|
||||
// Handles incoming requests.
|
||||
func handleRequest(conn net.Conn) {
|
||||
session := GameSpySession{
|
||||
Conn: conn,
|
||||
User: database.User{},
|
||||
ModuleName: "GPCM",
|
||||
LoggedIn: false,
|
||||
Status: "",
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
defer closeSession(&session)
|
||||
|
||||
// Set session ID and challenge
|
||||
challenge := common.RandomString(10)
|
||||
|
|
@ -118,7 +136,7 @@ func handleRequest(conn net.Conn) {
|
|||
|
||||
if session.LoggedIn == false {
|
||||
if command.Command != "login" {
|
||||
logging.Notice(session.ModuleName, "Attempt to run command before login!!!")
|
||||
logging.Notice(session.ModuleName, "Attempt to run command before login!")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -139,24 +157,19 @@ func handleRequest(conn net.Conn) {
|
|||
return
|
||||
|
||||
case "updatepro":
|
||||
UpdateProfile(&session, pool, ctx, command)
|
||||
updateProfile(&session, pool, ctx, command)
|
||||
break
|
||||
|
||||
case "status":
|
||||
logging.Notice(session.ModuleName, "statstring:", aurora.Cyan(command.OtherValues["statstring"]).String())
|
||||
if command.OtherValues["locstring"] == "" {
|
||||
logging.Notice(session.ModuleName, "locstring: (empty)")
|
||||
} else {
|
||||
logging.Notice(session.ModuleName, "locstring:", aurora.Cyan(command.OtherValues["locstring"]).String())
|
||||
}
|
||||
setStatus(&session, pool, ctx, command)
|
||||
break
|
||||
|
||||
case "addbuddy":
|
||||
AddFriend(&session, pool, ctx, command)
|
||||
addFriend(&session, pool, ctx, command)
|
||||
break
|
||||
|
||||
case "delbuddy":
|
||||
RemoveFriend(&session, pool, ctx, command)
|
||||
removeFriend(&session, pool, ctx, command)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -168,7 +181,7 @@ func handleRequest(conn net.Conn) {
|
|||
break
|
||||
|
||||
case "getprofile":
|
||||
payload := GetProfile(&session, pool, ctx, command)
|
||||
payload := getProfile(&session, pool, ctx, command)
|
||||
conn.Write([]byte(payload))
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,19 +5,23 @@ import (
|
|||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/logrusorgru/aurora/v3"
|
||||
"strconv"
|
||||
"strings"
|
||||
"wwfc/common"
|
||||
"wwfc/database"
|
||||
"wwfc/logging"
|
||||
)
|
||||
|
||||
func GetProfile(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) string {
|
||||
func getProfile(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) string {
|
||||
strProfileId := command.OtherValues["profileid"]
|
||||
profileId, err := strconv.ParseInt(strProfileId, 10, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
user := database.GetProfile(pool, ctx, uint32(profileId))
|
||||
user, ok := database.GetProfile(pool, ctx, uint32(profileId))
|
||||
if !ok {
|
||||
return `\pi\\final\`
|
||||
}
|
||||
|
||||
_ = common.RandomHexString(32)
|
||||
return common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
|
|
@ -28,7 +32,7 @@ func GetProfile(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context
|
|||
"nick": user.UniqueNick,
|
||||
"userid": strconv.FormatInt(user.UserId, 10),
|
||||
"email": user.Email,
|
||||
"sig": "b126556e5ee62d4da9629dfad0f6b2a8",
|
||||
"sig": common.RandomHexString(32),
|
||||
"uniquenick": user.UniqueNick,
|
||||
"firstname": user.FirstName,
|
||||
"lastname": user.LastName,
|
||||
|
|
@ -41,7 +45,7 @@ func GetProfile(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context
|
|||
})
|
||||
}
|
||||
|
||||
func UpdateProfile(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
|
||||
func updateProfile(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
|
||||
var firstName string
|
||||
var lastName string
|
||||
if v, ok := command.OtherValues["firstname"]; ok {
|
||||
|
|
@ -55,7 +59,62 @@ func UpdateProfile(session *GameSpySession, pool *pgxpool.Pool, ctx context.Cont
|
|||
database.UpdateUser(pool, ctx, firstName, lastName, session.User.UserId)
|
||||
}
|
||||
|
||||
func AddFriend(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
|
||||
func setStatus(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
|
||||
status := command.CommandValue
|
||||
|
||||
statstring, ok := command.OtherValues["statstring"]
|
||||
if !ok {
|
||||
logging.Notice(session.ModuleName, "Missing statstring")
|
||||
statstring = ""
|
||||
} else {
|
||||
if statstring == "" {
|
||||
logging.Notice(session.ModuleName, "statstring: (empty)")
|
||||
} else {
|
||||
logging.Notice(session.ModuleName, "statstring:", aurora.Cyan(statstring).String())
|
||||
}
|
||||
}
|
||||
|
||||
locstring, ok := command.OtherValues["locstring"]
|
||||
if !ok {
|
||||
logging.Notice(session.ModuleName, "Missing locstring")
|
||||
locstring = ""
|
||||
} else {
|
||||
if locstring == "" {
|
||||
logging.Notice(session.ModuleName, "locstring: (empty)")
|
||||
} else {
|
||||
logging.Notice(session.ModuleName, "locstring:", aurora.Cyan(locstring).String())
|
||||
}
|
||||
}
|
||||
|
||||
// Get the IP address for the status msg
|
||||
var rawIP int
|
||||
for i, s := range strings.Split(strings.Split(session.Conn.RemoteAddr().String(), ":")[0], ".") {
|
||||
val, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rawIP |= val << (24 - i*8)
|
||||
}
|
||||
|
||||
// TODO: Check if this handles negative numbers correctly
|
||||
ip := strconv.FormatInt(int64(int32(rawIP)), 10)
|
||||
|
||||
friendStatus := common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
Command: "bm",
|
||||
CommandValue: "100",
|
||||
OtherValues: map[string]string{
|
||||
"f": strconv.FormatUint(uint64(session.User.ProfileId), 10),
|
||||
"msg": "|s|" + status + "|ss|" + statstring + "|ls|" + locstring + "|ip|" + ip + "|p|0|qm|0",
|
||||
},
|
||||
})
|
||||
|
||||
mutex.Lock()
|
||||
session.Status = friendStatus
|
||||
mutex.Unlock()
|
||||
}
|
||||
|
||||
func addFriend(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
|
||||
strProfileId := command.OtherValues["newprofileid"]
|
||||
profileId, err := strconv.ParseUint(strProfileId, 10, 32)
|
||||
if err != nil {
|
||||
|
|
@ -67,17 +126,6 @@ func AddFriend(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context,
|
|||
// TODO
|
||||
}
|
||||
|
||||
func RemoveFriend(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
|
||||
func removeFriend(session *GameSpySession, pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func createStatus() string {
|
||||
return common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
Command: "bm",
|
||||
CommandValue: "100",
|
||||
OtherValues: map[string]string{
|
||||
"f": "5",
|
||||
"msg": "|s|0|ss|Offline",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@ import (
|
|||
|
||||
var (
|
||||
// I would use a sync.Map instead of the map mutex combo, but this performs better.
|
||||
sessions = map[uint32]*Session{}
|
||||
mutex = sync.RWMutex{}
|
||||
sessions = map[uint32]*Session{}
|
||||
mutex = sync.RWMutex{}
|
||||
masterConn net.PacketConn
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -41,6 +42,8 @@ func StartServer() {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
masterConn = conn
|
||||
|
||||
// Close the listener when the application closes.
|
||||
defer conn.Close()
|
||||
logging.Notice("MASTER", "Listening on", address)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
package master
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"github.com/logrusorgru/aurora/v3"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"wwfc/logging"
|
||||
)
|
||||
|
|
@ -14,6 +18,7 @@ const (
|
|||
|
||||
type Session struct {
|
||||
SessionID uint32
|
||||
Addr net.Addr
|
||||
Challenge string
|
||||
Authenticated bool
|
||||
LastKeepAlive int64
|
||||
|
|
@ -43,22 +48,23 @@ func setSessionData(sessionId uint32, payload map[string]string) Session {
|
|||
Data: payload,
|
||||
}
|
||||
sessions[sessionId] = &data
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
session.Data = payload
|
||||
session.LastKeepAlive = time.Now().Unix()
|
||||
|
||||
return *session
|
||||
}
|
||||
|
||||
// Get a copy of the list of servers
|
||||
func GetSessionServers() []map[string]string {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
var servers []map[string]string
|
||||
currentTime := time.Now().Unix()
|
||||
|
||||
var servers []map[string]string
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
for _, session := range sessions {
|
||||
if !session.Authenticated {
|
||||
continue
|
||||
|
|
@ -74,3 +80,55 @@ func GetSessionServers() []map[string]string {
|
|||
|
||||
return servers
|
||||
}
|
||||
|
||||
func SendClientMessage(destIP string, message []byte) {
|
||||
var rawIP int
|
||||
for i, s := range strings.Split(strings.Split(destIP, ":")[0], ".") {
|
||||
val, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rawIP |= val << (24 - i*8)
|
||||
}
|
||||
|
||||
// TODO: Check if this handles negative numbers correctly
|
||||
destIPIntStr := strconv.FormatInt(int64(int32(rawIP)), 10)
|
||||
|
||||
currentTime := time.Now().Unix()
|
||||
|
||||
mutex.Lock()
|
||||
// Find the session with the IP
|
||||
for _, session := range sessions {
|
||||
if !session.Authenticated {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the last keep alive was over a minute ago then consider the server unreachable
|
||||
if session.LastKeepAlive < currentTime-60 {
|
||||
continue
|
||||
}
|
||||
|
||||
if session.Data["publicip"] == destIPIntStr {
|
||||
// Found the client, now send the message
|
||||
payload := createResponseHeader(ClientMessageRequest, session.SessionID)
|
||||
mutex.Unlock()
|
||||
|
||||
payload = append(payload, []byte{0, 0, 0, 0}...)
|
||||
binary.BigEndian.PutUint32(payload[len(payload)-4:], uint32(time.Now().Unix()))
|
||||
payload = append(payload, message...)
|
||||
|
||||
destIPAddr, err := net.ResolveUDPAddr("udp", destIP)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
logging.Notice("MASTER", "Sending message...")
|
||||
masterConn.WriteTo(payload, destIPAddr)
|
||||
return
|
||||
}
|
||||
}
|
||||
mutex.Unlock()
|
||||
|
||||
logging.Notice("MASTER", "Could not find destination server")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package matchmaking
|
|||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
|
|
@ -95,20 +96,50 @@ func handleRequest(conn net.Conn) {
|
|||
}
|
||||
|
||||
// Here we go into the listening loop
|
||||
bufferSize := 0
|
||||
packetSize := uint16(0)
|
||||
buffer := []byte{}
|
||||
for {
|
||||
buffer := make([]byte, 1024)
|
||||
_, err := bufio.NewReader(conn).Read(buffer)
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
// Client closed connection, terminate.
|
||||
// Remove stale data and remake the buffer
|
||||
buffer = append(buffer[packetSize:], make([]byte, 1024-packetSize)...)
|
||||
bufferSize -= int(packetSize)
|
||||
packetSize = 0
|
||||
|
||||
for {
|
||||
if bufferSize > 2 {
|
||||
packetSize = binary.BigEndian.Uint16(buffer[:2])
|
||||
if packetSize < 3 {
|
||||
logging.Notice(ModuleName, "Invalid packet size - terminating")
|
||||
return
|
||||
}
|
||||
|
||||
if bufferSize >= int(packetSize) {
|
||||
// Got a full packet, break to continue
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
readSize, err := bufio.NewReader(conn).Read(buffer[bufferSize:])
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
logging.Notice(ModuleName, "Connection closed")
|
||||
return
|
||||
}
|
||||
|
||||
logging.Notice(ModuleName, "Connection error")
|
||||
return
|
||||
}
|
||||
|
||||
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())
|
||||
handleServerListRequest(conn, buffer)
|
||||
handleServerListRequest(conn, buffer[:packetSize])
|
||||
break
|
||||
|
||||
case ServerInfoRequest:
|
||||
|
|
@ -117,7 +148,7 @@ func handleRequest(conn net.Conn) {
|
|||
|
||||
case SendMessageRequest:
|
||||
logging.Notice(ModuleName, "Command:", aurora.Yellow("SEND_MESSAGE_REQUEST").String())
|
||||
// TODO
|
||||
handleSendMessageRequest(conn, buffer[:packetSize])
|
||||
break
|
||||
|
||||
case KeepaliveReply:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package matchmaking
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/logrusorgru/aurora/v3"
|
||||
"net"
|
||||
"strconv"
|
||||
|
|
@ -238,3 +239,15 @@ func handleServerListRequest(conn net.Conn, buffer []byte) {
|
|||
// Write the encrypted reply
|
||||
conn.Write(common.EncryptTypeX([]byte("9r3Rmy"), challenge, output))
|
||||
}
|
||||
|
||||
func handleSendMessageRequest(conn net.Conn, buffer []byte) {
|
||||
// Read destination IP from buffer
|
||||
destIP := fmt.Sprintf("%d.%d.%d.%d:%d", buffer[3], buffer[4], buffer[5], buffer[6], binary.BigEndian.Uint16(buffer[7:9]))
|
||||
|
||||
logging.Notice(ModuleName, "Send message from", aurora.Cyan(conn.RemoteAddr()).String(), "to", aurora.Cyan(destIP).String())
|
||||
|
||||
// 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:])
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user