mirror of
https://github.com/WiiLink24/wfc-server.git
synced 2026-07-27 13:44:25 -05:00
135 lines
3.0 KiB
Go
135 lines
3.0 KiB
Go
package master
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"github.com/logrusorgru/aurora/v3"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
"wwfc/logging"
|
|
)
|
|
|
|
const (
|
|
ClientNoEndian = iota
|
|
ClientBigEndian
|
|
ClientLittleEndian
|
|
)
|
|
|
|
type Session struct {
|
|
SessionID uint32
|
|
Addr net.Addr
|
|
Challenge string
|
|
Authenticated bool
|
|
LastKeepAlive int64
|
|
Endianness byte // Some fields depend on the client's endianness
|
|
Data map[string]string
|
|
}
|
|
|
|
// Remove a session.
|
|
func removeSession(sessionId uint32) {
|
|
delete(sessions, sessionId)
|
|
}
|
|
|
|
// Update session data, creating the session if it doesn't exist. Returns a copy of the session data.
|
|
func setSessionData(sessionId uint32, payload map[string]string) Session {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
|
|
session, exists := sessions[sessionId]
|
|
if !exists {
|
|
logging.Notice("MASTER", "Creating session", aurora.Cyan(sessionId).String())
|
|
data := Session{
|
|
SessionID: sessionId,
|
|
Challenge: "",
|
|
Authenticated: false,
|
|
LastKeepAlive: time.Now().Unix(),
|
|
Endianness: ClientNoEndian,
|
|
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 {
|
|
var servers []map[string]string
|
|
currentTime := time.Now().Unix()
|
|
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
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
|
|
}
|
|
|
|
servers = append(servers, session.Data)
|
|
}
|
|
|
|
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")
|
|
}
|