wfc-server/serverbrowser/main.go

168 lines
3.5 KiB
Go

package serverbrowser
import (
"encoding/binary"
"encoding/gob"
"os"
"wwfc/common"
"wwfc/logging"
"github.com/linkdata/deadlock"
"github.com/logrusorgru/aurora/v3"
)
var ServerName = "serverbrowser"
const (
// Requests sent from the client
ServerListRequest = 0x00
ServerInfoRequest = 0x01
SendMessageRequest = 0x02
KeepaliveReply = 0x03
MapLoopRequest = 0x04
PlayerSearchRequest = 0x05
// Requests sent from the server to the client
PushKeysMessage = 0x01
PushServerMessage = 0x02
KeepaliveMessage = 0x03
DeleteServerMessage = 0x04
MapLoopMessage = 0x05
PlayerSearchMessage = 0x06
)
var (
connBuffers = map[uint64]*[]byte{}
mutex = deadlock.RWMutex{}
)
func StartServer(reload bool) {
if !reload {
return
}
// Load connection state
file, err := os.Open("state/sb_connections.gob")
if err != nil {
panic(err)
}
decoder := gob.NewDecoder(file)
err = decoder.Decode(&connBuffers)
file.Close()
if err != nil {
panic(err)
}
logging.Notice("SB", "Loaded", aurora.Cyan(len(connBuffers)), "connections")
}
func Shutdown() {
// Save connection state
file, err := os.OpenFile("state/sb_connections.gob", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
panic(err)
}
encoder := gob.NewEncoder(file)
err = encoder.Encode(connBuffers)
file.Close()
if err != nil {
panic(err)
}
logging.Notice("SB", "Saved", aurora.Cyan(len(connBuffers)), "connections")
}
func NewConnection(index uint64, address string) {
}
func CloseConnection(index uint64) {
mutex.Lock()
delete(connBuffers, index)
mutex.Unlock()
}
func HandlePacket(index uint64, data []byte, address string) {
moduleName := "SB:" + address
mutex.RLock()
buffer := connBuffers[index]
mutex.RUnlock()
if buffer == nil {
buffer = &[]byte{}
defer func() {
if buffer == nil {
return
}
mutex.Lock()
connBuffers[index] = buffer
mutex.Unlock()
}()
}
if len(*buffer)+len(data) > 0x1000 {
logging.Error(moduleName, "Buffer overflow")
common.CloseConnection(ServerName, index)
buffer = nil
return
}
*buffer = append(*buffer, data...)
// Packets can be sent in fragments, so we need to check if we have a full packet
// The first two bytes signify the packet size
if len(*buffer) < 2 {
return
}
packetSize := binary.BigEndian.Uint16((*buffer)[:2])
if packetSize < 3 || packetSize > 0x1000 {
logging.Error(moduleName, "Invalid packet size - terminating")
common.CloseConnection(ServerName, index)
buffer = nil
return
}
if len(*buffer) < int(packetSize) {
return
}
switch (*buffer)[2] {
case ServerListRequest:
// logging.Info(moduleName, "Command:", aurora.Yellow("SERVER_LIST_REQUEST"))
handleServerListRequest(moduleName, index, address, (*buffer)[:packetSize])
case ServerInfoRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("SERVER_INFO_REQUEST"))
case SendMessageRequest:
// logging.Info(moduleName, "Command:", aurora.Yellow("SEND_MESSAGE_REQUEST"))
handleSendMessageRequest(moduleName, index, address, (*buffer)[:packetSize])
case KeepaliveReply:
logging.Info(moduleName, "Command:", aurora.Yellow("KEEPALIVE_REPLY"))
case MapLoopRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("MAPLOOP_REQUEST"))
case PlayerSearchRequest:
logging.Info(moduleName, "Command:", aurora.Yellow("PLAYER_SEARCH_REQUEST"))
default:
logging.Error(moduleName, "Unknown command:", aurora.Cyan((*buffer)[2]))
}
if len(*buffer) > int(packetSize) {
*buffer = (*buffer)[packetSize:]
} else {
*buffer = []byte{}
buffer = nil
}
}