Use new RUDP version

master
HimbeerserverDE 2021-03-29 18:57:30 +02:00
parent bb337e00c3
commit 1540fd54f5
No known key found for this signature in database
GPG Key ID: 1A651504791E6A8B
23 changed files with 1208 additions and 849 deletions

View File

@ -1,6 +1,7 @@
package main
import (
"bytes"
"encoding/binary"
"log"
@ -23,20 +24,23 @@ const (
AoCmdSetAnimSpeed
)
func processAoRmAdd(p *Peer, data []byte) []byte {
countRm := binary.BigEndian.Uint16(data[2:4])
func processAoRmAdd(c *Conn, r *bytes.Reader) []byte {
data := make([]byte, r.Len())
r.Read(data)
countRm := binary.BigEndian.Uint16(data[0:2])
var aoRm []uint16
for i := uint16(0); i < countRm; i += 2 {
id := binary.BigEndian.Uint16(data[4+i : 6+i])
if id == p.localPlayerCao {
id = p.currentPlayerCao
id := binary.BigEndian.Uint16(data[2+i : 4+i])
if id == c.localPlayerCao {
id = c.currentPlayerCao
}
aoRm = append(aoRm, id)
}
countAdd := binary.BigEndian.Uint16(data[4+countRm*2 : 6+countRm*2])
countAdd := binary.BigEndian.Uint16(data[2+countRm*2 : 4+countRm*2])
var aoAdd []uint16
si := 6 + uint32(countRm)*2
si := 4 + uint32(countRm)*2
for i := uint32(0); i < uint32(countAdd); i++ {
id := binary.BigEndian.Uint16(data[si : 2+si])
@ -44,8 +48,8 @@ func processAoRmAdd(p *Peer, data []byte) []byte {
namelen := binary.BigEndian.Uint16(data[8+si : 10+si])
name := data[10+si : 10+si+uint32(namelen)]
if string(name) == p.Username() {
if p.initAoReceived {
if string(name) == c.Username() {
if c.initAoReceived {
initData := data[7+si : 7+si+initDataLen]
// Read the messages from the packet
@ -65,13 +69,13 @@ func processAoRmAdd(p *Peer, data []byte) []byte {
msgpkt := []byte{0x00, ToClientActiveObjectMessages}
for _, msg := range msgs {
msgdata := make([]byte, 4+len(msg))
binary.BigEndian.PutUint16(msgdata[0:2], p.localPlayerCao)
binary.BigEndian.PutUint16(msgdata[0:2], c.localPlayerCao)
binary.BigEndian.PutUint16(msgdata[2:4], uint16(len(msg)))
copy(msgdata[4:], aoMsgReplaceIDs(p, msg))
copy(msgdata[4:], aoMsgReplaceIDs(c, msg))
msgpkt = append(msgpkt, msgdata...)
}
ack, err := p.Send(rudp.Pkt{Data: msgpkt})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(msgpkt)})
if err != nil {
log.Print(err)
}
@ -79,18 +83,18 @@ func processAoRmAdd(p *Peer, data []byte) []byte {
binary.BigEndian.PutUint16(data[4+countRm*2:6+countRm*2], countAdd-1)
data = append(data[:si], data[7+si+initDataLen:]...)
p.currentPlayerCao = id
c.currentPlayerCao = id
si -= 7 + initDataLen
} else {
p.initAoReceived = true
p.localPlayerCao = id
p.currentPlayerCao = id
c.initAoReceived = true
c.localPlayerCao = id
c.currentPlayerCao = id
}
si += 7 + initDataLen
continue
} else if id == p.localPlayerCao {
id = p.currentPlayerCao
} else if id == c.localPlayerCao {
id = c.currentPlayerCao
binary.BigEndian.PutUint16(data[si:2+si], id)
}
@ -99,63 +103,68 @@ func processAoRmAdd(p *Peer, data []byte) []byte {
si += 7 + initDataLen
}
p.redirectMu.Lock()
c.redirectMu.Lock()
for i := range aoAdd {
if aoAdd[i] != 0 {
p.aoIDs[aoAdd[i]] = true
c.aoIDs[aoAdd[i]] = true
}
}
for i := range aoRm {
p.aoIDs[aoRm[i]] = false
c.aoIDs[aoRm[i]] = false
}
p.redirectMu.Unlock()
c.redirectMu.Unlock()
return data
}
func processAoMsgs(p *Peer, data []byte) []byte {
si := uint32(2)
func processAoMsgs(c *Conn, r *bytes.Reader) []byte {
data := make([]byte, r.Len())
r.Read(data)
si := uint32(0)
for si < uint32(len(data)) {
id := binary.BigEndian.Uint16(data[si : 2+si])
msglen := binary.BigEndian.Uint16(data[2+si : 4+si])
msg := data[4+si : 4+si+uint32(msglen)]
msg = aoMsgReplaceIDs(p, msg)
msg = aoMsgReplaceIDs(c, msg)
copy(data[4+si:4+si+uint32(msglen)], msg)
if id == p.currentPlayerCao {
id = p.localPlayerCao
if id == c.currentPlayerCao {
id = c.localPlayerCao
binary.BigEndian.PutUint16(data[si:2+si], id)
} else if id == p.localPlayerCao {
id = p.currentPlayerCao
} else if id == c.localPlayerCao {
id = c.currentPlayerCao
binary.BigEndian.PutUint16(data[si:2+si], id)
}
si += 4 + uint32(msglen)
}
return data
}
func aoMsgReplaceIDs(p *Peer, data []byte) []byte {
func aoMsgReplaceIDs(c *Conn, data []byte) []byte {
switch cmd := data[0]; cmd {
case AoCmdAttachTo:
id := binary.BigEndian.Uint16(data[1:3])
if id == p.currentPlayerCao {
id = p.localPlayerCao
if id == c.currentPlayerCao {
id = c.localPlayerCao
binary.BigEndian.PutUint16(data[1:3], id)
} else if id == p.localPlayerCao {
id = p.currentPlayerCao
} else if id == c.localPlayerCao {
id = c.currentPlayerCao
binary.BigEndian.PutUint16(data[1:3], id)
}
case AoCmdSpawnInfant:
id := binary.BigEndian.Uint16(data[1:3])
if id == p.currentPlayerCao {
id = p.localPlayerCao
if id == c.currentPlayerCao {
id = c.localPlayerCao
binary.BigEndian.PutUint16(data[1:3], id)
} else if id == p.localPlayerCao {
id = p.currentPlayerCao
} else if id == c.localPlayerCao {
id = c.currentPlayerCao
binary.BigEndian.PutUint16(data[1:3], id)
}
}
return data
}

24
ban.go
View File

@ -1,6 +1,7 @@
package main
import (
"bytes"
"database/sql"
"encoding/binary"
"errors"
@ -116,15 +117,15 @@ func BanList() (map[string]string, error) {
return r, nil
}
// IsBanned reports whether a Peer is banned
func (p *Peer) IsBanned() (bool, string, error) {
// IsBanned reports whether a Conn is banned
func (c *Conn) IsBanned() (bool, string, error) {
db, err := initAuthDB()
if err != nil {
return true, "", err
}
defer db.Close()
addr := p.Addr().(*net.UDPAddr).IP.String()
addr := c.Addr().(*net.UDPAddr).IP.String()
name, err := readBanItem(db, addr)
if err != nil {
@ -134,15 +135,15 @@ func (p *Peer) IsBanned() (bool, string, error) {
return name != "", name, nil
}
// Ban adds a Peer to the ban list
func (p *Peer) Ban() error {
banned, _, err := p.IsBanned()
// Ban adds a Conn to the ban list
func (c *Conn) Ban() error {
banned, _, err := c.IsBanned()
if err != nil {
return err
}
if banned {
return fmt.Errorf("ip address %s is already banned", p.Addr().String())
return fmt.Errorf("ip address %s is already banned", c.Addr().String())
}
db, err := initAuthDB()
@ -151,8 +152,8 @@ func (p *Peer) Ban() error {
}
defer db.Close()
name := p.Username()
addr := p.Addr().(*net.UDPAddr).IP.String()
name := c.Username()
addr := c.Addr().(*net.UDPAddr).IP.String()
err = addBanItem(db, addr, name)
if err != nil {
@ -171,14 +172,13 @@ func (p *Peer) Ban() error {
data[5+l] = uint8(0x00)
data[6+l] = uint8(0x00)
ack, err := p.Send(rudp.Pkt{Data: data})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
<-ack
p.SendDisco(0, true)
p.Close()
c.Close()
return nil
}

View File

@ -5,32 +5,33 @@ import (
"compress/zlib"
"encoding/binary"
"io"
"github.com/anon55555/mt/rudp"
)
const NodeCount = 16 * 16 * 16
func processBlockdata(p *Peer, pkt *rudp.Pkt) bool {
srv := p.ServerName()
func processBlockdata(c *Conn, r *bytes.Reader) ([]byte, bool) {
srv := c.ServerName()
x := int16(binary.BigEndian.Uint16(pkt.Data[2:4]))
y := int16(binary.BigEndian.Uint16(pkt.Data[4:6]))
z := int16(binary.BigEndian.Uint16(pkt.Data[6:8]))
posData := make([]byte, 6)
r.Read(posData)
p.blocks = append(p.blocks, [3]int16{x, y, z})
x := int16(binary.BigEndian.Uint16(posData[0:2]))
y := int16(binary.BigEndian.Uint16(posData[2:4]))
z := int16(binary.BigEndian.Uint16(posData[4:6]))
r := bytes.NewReader(pkt.Data[13:])
c.blocks = append(c.blocks, [3]int16{x, y, z})
r.Seek(13, io.SeekStart)
zr, err := zlib.NewReader(r)
if err != nil {
return true
return nil, true
}
buf := &bytes.Buffer{}
_, err = io.Copy(buf, zr)
if err != nil {
return true
return nil, true
}
zr.Close()
@ -52,30 +53,39 @@ func processBlockdata(p *Peer, pkt *rudp.Pkt) bool {
recompNodes := recompBuf.Bytes()
meta := make([]byte, 65536)
n, err := r.Read(meta)
if err != nil {
return true
}
meta := make([]byte, r.Len())
r.Read(meta)
meta = meta[:n]
r.Seek(2, io.SeekStart)
data := make([]byte, 13+len(recompNodes)+len(meta))
copy(data[:13], pkt.Data[:13])
copy(data[13:13+len(recompNodes)], recompNodes)
copy(data[13+len(recompNodes):], meta)
blockMeta := make([]byte, 11)
r.Read(blockMeta)
pkt.Data = data
data := make([]byte, 11+len(recompNodes)+len(meta))
copy(data[:11], blockMeta)
copy(data[11:11+len(recompNodes)], recompNodes)
copy(data[11+len(recompNodes):], meta)
return false
return data, false
}
func processAddnode(p *Peer, pkt *rudp.Pkt) bool {
srv := p.ServerName()
func processAddnode(c *Conn, r *bytes.Reader) []byte {
srv := c.ServerName()
contentID := binary.BigEndian.Uint16(pkt.Data[8:10])
r.Seek(8, io.SeekStart)
idBytes := make([]byte, 2)
r.Read(idBytes)
contentID := binary.BigEndian.Uint16(idBytes)
newID := NodeDefs()[srv][contentID].ID()
binary.BigEndian.PutUint16(pkt.Data[8:10], newID)
return false
r.Seek(2, io.SeekStart)
data := make([]byte, r.Len())
r.Read(data)
binary.BigEndian.PutUint16(data[6:8], newID)
return data
}

60
chat.go
View File

@ -1,7 +1,9 @@
package main
import (
"bytes"
"encoding/binary"
"io"
"log"
"strings"
"time"
@ -15,17 +17,17 @@ var ChatCommandPrefix string = "#"
type chatCommand struct {
help string
privs map[string]bool
function func(*Peer, string)
function func(*Conn, string)
}
var chatCommands map[string]chatCommand
var onChatMsg []func(*Peer, string) bool
var onChatMsg []func(*Conn, string) bool
var onServerChatMsg []func(*Peer, string) bool
var onServerChatMsg []func(*Conn, string) bool
// RegisterChatCommand registers a callback function that is called
// when a client executes the command and has the required privileges
func RegisterChatCommand(name string, privs map[string]bool, help string, function func(*Peer, string)) {
func RegisterChatCommand(name string, privs map[string]bool, help string, function func(*Conn, string)) {
chatCommands[name] = chatCommand{
privs: privs,
help: help,
@ -40,7 +42,7 @@ func (c chatCommand) Help() string { return c.help }
// when a client sends a chat message
// If a callback function returns true the message is not forwarded
// to the minetest server
func RegisterOnChatMessage(function func(*Peer, string) bool) {
func RegisterOnChatMessage(function func(*Conn, string) bool) {
onChatMsg = append(onChatMsg, function)
}
@ -48,19 +50,24 @@ func RegisterOnChatMessage(function func(*Peer, string) bool) {
// that is called when a server sends a chat message
// If a callback function returns true the message is not forwarded
// to the minetest clients
func RegisterOnServerChatMessage(function func(*Peer, string) bool) {
func RegisterOnServerChatMessage(function func(*Conn, string) bool) {
onServerChatMsg = append(onServerChatMsg, function)
}
func processChatMessage(p *Peer, pkt rudp.Pkt) bool {
s := string(narrow(pkt.Data[4:]))
func processChatMessage(c *Conn, pkt rudp.Pkt) bool {
r := ByteReader(pkt)
wstr := make([]byte, r.Len()-4)
r.ReadAt(wstr, 4)
s := string(narrow(wstr))
if strings.HasPrefix(s, ChatCommandPrefix) {
// Chat command
s = strings.Replace(s, ChatCommandPrefix, "", 1)
params := strings.Split(s, " ")
// Priv check
allow, err := p.CheckPrivs(chatCommands[params[0]].privs)
allow, err := c.CheckPrivs(chatCommands[params[0]].privs)
if err != nil {
log.Print(err)
return true
@ -85,7 +92,7 @@ func processChatMessage(p *Peer, pkt rudp.Pkt) bool {
data[11+len(wstr)] = uint8(0x00)
binary.BigEndian.PutUint32(data[12+len(wstr):16+len(wstr)], uint32(time.Now().Unix()))
ack, err := p.Send(rudp.Pkt{Data: data})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
@ -115,7 +122,7 @@ func processChatMessage(p *Peer, pkt rudp.Pkt) bool {
data[11+len(wstr)] = uint8(0x00)
binary.BigEndian.PutUint32(data[12+len(wstr):16+len(wstr)], uint32(time.Now().Unix()))
ack, err := p.Send(rudp.Pkt{Data: data})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
@ -124,13 +131,13 @@ func processChatMessage(p *Peer, pkt rudp.Pkt) bool {
return true
}
chatCommands[params[0]].function(p, strings.Join(params[1:], " "))
chatCommands[params[0]].function(c, strings.Join(params[1:], " "))
return true
} else {
// Regular message
noforward := false
for i := range onChatMsg {
if onChatMsg[i](p, s) {
if onChatMsg[i](c, s) {
noforward = true
}
}
@ -138,20 +145,27 @@ func processChatMessage(p *Peer, pkt rudp.Pkt) bool {
}
}
func processServerChatMessage(p *Peer, pkt rudp.Pkt) bool {
s := string(narrow(pkt.Data[4:]))
func processServerChatMessage(c *Conn, pkt rudp.Pkt) bool {
r := ByteReader(pkt)
r.Seek(4, io.SeekStart)
wstr := make([]byte, r.Len())
r.Read(wstr)
s := string(narrow(wstr))
noforward := false
for i := range onServerChatMsg {
if onServerChatMsg[i](p, s) {
if onServerChatMsg[i](c, s) {
noforward = true
}
}
return noforward
}
// SendChatMsg sends a chat message to the Peer if it isn't a server
func (p *Peer) SendChatMsg(msg string) {
if p.IsSrv() {
// SendChatMsg sends a chat message to a Conn if it isn't a server
func (c *Conn) SendChatMsg(msg string) {
if c.IsSrv() {
return
}
@ -172,17 +186,17 @@ func (p *Peer) SendChatMsg(msg string) {
data[11+len(wstr)] = uint8(0x00)
binary.BigEndian.PutUint32(data[12+len(wstr):16+len(wstr)], uint32(time.Now().Unix()))
ack, err := p.Send(rudp.Pkt{Data: data})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
<-ack
}
// ChatSendAll sends a chat message to all connected client Peers
// ChatSendAll sends a chat message to all connected client Conns
func ChatSendAll(msg string) {
for _, p := range Peers() {
go p.SendChatMsg(msg)
for _, c := range Conns() {
go c.SendChatMsg(msg)
}
}

View File

@ -4,6 +4,7 @@ import (
"bytes"
"crypto/subtle"
"encoding/binary"
"io"
"log"
"github.com/HimbeerserverDE/srp"
@ -112,19 +113,37 @@ const (
AccessDeniedCrash
)
func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
func processPktCommand(src, dst *Conn, pkt *rudp.Pkt) bool {
r := ByteReader(*pkt)
origReader := *r
pkt.Reader = &origReader
cmdBytes := make([]byte, 2)
r.Read(cmdBytes)
if src.IsSrv() {
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
switch cmd := binary.BigEndian.Uint16(cmdBytes); cmd {
case ToClientActiveObjectRemoveAdd:
pkt.Data = processAoRmAdd(dst, pkt.Data)
pkt.Reader = bytes.NewReader(append(cmdBytes, processAoRmAdd(dst, r)...))
return false
case ToClientActiveObjectMessages:
pkt.Data = processAoMsgs(dst, pkt.Data)
pkt.Reader = bytes.NewReader(append(cmdBytes, processAoMsgs(dst, r)...))
return false
case ToClientChatMessage:
namelen := binary.BigEndian.Uint16(pkt.Data[4:6])
msglen := binary.BigEndian.Uint16(pkt.Data[6+namelen : 8+namelen])
msg := pkt.Data[8+namelen:]
r.Seek(2, io.SeekCurrent)
namelenBytes := make([]byte, 2)
r.Read(namelenBytes)
namelen := binary.BigEndian.Uint16(namelenBytes)
r.Seek(int64(namelen), io.SeekCurrent)
msglenBytes := make([]byte, 2)
r.Read(msglenBytes)
msglen := binary.BigEndian.Uint16(msglenBytes)
msg := make([]byte, r.Len())
r.Read(msg)
data := make([]byte, 4+msglen*2)
data[0] = uint8(0x00)
@ -132,64 +151,134 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
binary.BigEndian.PutUint16(data[2:4], uint16(msglen))
copy(data[4:], msg)
return processServerChatMessage(dst, rudp.Pkt{Data: data, ChNo: pkt.ChNo})
return processServerChatMessage(dst, rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: pkt.Channel,
},
})
case ToClientModChannelSignal:
chlen := binary.BigEndian.Uint16(pkt.Data[3:5])
ch := string(pkt.Data[5 : 5+chlen])
r.Seek(1, io.SeekCurrent)
chlenBytes := make([]byte, 2)
r.Read(chlenBytes)
chlen := binary.BigEndian.Uint16(chlenBytes)
chBytes := make([]byte, chlen)
r.Read(chBytes)
state, _ := r.ReadByte()
r.Seek(2, io.SeekStart)
ch := string(chBytes)
if ch == rpcCh {
switch sig := pkt.Data[2]; sig {
switch sig, _ := r.ReadByte(); sig {
case ModChSigJoinOk:
src.SetUseRpc(true)
case ModChSigSetState:
state := pkt.Data[5+chlen]
if state == ModChStateRO {
src.SetUseRpc(false)
}
}
return true
}
return false
case ToClientModChannelMsg:
return processRpc(src, *pkt)
return processRpc(src, r)
case ToClientBlockdata:
return processBlockdata(dst, pkt)
data, drop := processBlockdata(dst, r)
if drop {
return true
}
pkt.Reader = bytes.NewReader(append(cmdBytes, data...))
return false
case ToClientAddNode:
return processAddnode(dst, pkt)
pkt.Reader = bytes.NewReader(append(cmdBytes, processAddnode(dst, r)...))
return false
case ToClientHudAdd:
id := binary.BigEndian.Uint32(pkt.Data[2:6])
idBytes := make([]byte, 4)
r.Read(idBytes)
id := binary.BigEndian.Uint32(idBytes)
dst.huds[id] = true
return false
case ToClientHudRm:
id := binary.BigEndian.Uint32(pkt.Data[2:6])
idBytes := make([]byte, 4)
r.Read(idBytes)
id := binary.BigEndian.Uint32(idBytes)
dst.huds[id] = false
return false
case ToClientPlaySound:
id := int32(binary.BigEndian.Uint32(pkt.Data[2:6]))
namelen := binary.BigEndian.Uint16(pkt.Data[6:8])
objID := binary.BigEndian.Uint16(pkt.Data[17+namelen : 19+namelen])
idBytes := make([]byte, 4)
r.Read(idBytes)
id := int32(binary.BigEndian.Uint32(idBytes))
namelenBytes := make([]byte, 2)
r.Read(namelenBytes)
namelen := binary.BigEndian.Uint16(namelenBytes)
r.Seek(int64(17+namelen), io.SeekStart)
objIDBytes := make([]byte, 2)
r.Read(objIDBytes)
objID := binary.BigEndian.Uint16(objIDBytes)
if objID == dst.currentPlayerCao {
objID = dst.localPlayerCao
} else if objID == dst.localPlayerCao {
objID = dst.currentPlayerCao
}
binary.BigEndian.PutUint16(pkt.Data[17+namelen:19+namelen], objID)
if loop := pkt.Data[19+namelen]; loop > 0 {
r.Seek(2, io.SeekStart)
data := make([]byte, r.Len())
r.Read(data)
binary.BigEndian.PutUint16(data[17+namelen:19+namelen], objID)
pkt.Reader = bytes.NewReader(append(cmdBytes, data...))
if loop, _ := r.ReadByte(); loop > 0 {
dst.sounds[id] = true
}
case ToClientStopSound:
id := int32(binary.BigEndian.Uint32(pkt.Data[2:6]))
idBytes := make([]byte, 4)
r.Read(idBytes)
id := int32(binary.BigEndian.Uint32(idBytes))
dst.sounds[id] = false
case ToClientAddParticlespawner:
texturelen := binary.BigEndian.Uint32(pkt.Data[97:101])
id := binary.BigEndian.Uint16(pkt.Data[107+texturelen : 109+texturelen])
r.Seek(97, io.SeekStart)
texturelenBytes := make([]byte, 4)
r.Read(texturelenBytes)
texturelen := binary.BigEndian.Uint32(texturelenBytes)
r.Seek(int64(6+texturelen), io.SeekCurrent)
idBytes := make([]byte, 2)
r.Read(idBytes)
id := binary.BigEndian.Uint16(idBytes)
if id == dst.currentPlayerCao {
id = dst.localPlayerCao
} else if id == dst.localPlayerCao {
id = dst.currentPlayerCao
}
binary.BigEndian.PutUint16(pkt.Data[107+texturelen:109+texturelen], id)
r.Seek(2, io.SeekStart)
data := make([]byte, r.Len())
r.Read(data)
binary.BigEndian.PutUint16(data[107+texturelen:109+texturelen], id)
pkt.Reader = bytes.NewReader(append(cmdBytes, data...))
case ToClientInventory:
if err := dst.Inv().Deserialize(bytes.NewReader(pkt.Data[2:])); err != nil {
if err := dst.Inv().Deserialize(r); err != nil {
return true
}
@ -198,7 +287,7 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
buf := &bytes.Buffer{}
dst.Inv().Serialize(buf)
pkt.Data = append(pkt.Data[:2], buf.Bytes()...)
pkt.Reader = bytes.NewReader(append(cmdBytes, buf.Bytes()...))
return false
case ToClientAccessDenied:
@ -207,12 +296,14 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
return false
}
if pkt.Data[2] != uint8(11) && pkt.Data[2] != uint8(12) {
reason, _ := r.ReadByte()
if reason != uint8(11) && reason != uint8(12) {
return false
}
msg := "shut down"
if pkt.Data[2] == uint8(12) {
if reason == uint8(12) {
msg = "crashed"
}
@ -235,12 +326,27 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
return true
case ToClientMediaPush:
digLen := binary.BigEndian.Uint16(pkt.Data[2:4])
digest := pkt.Data[4 : 4+digLen]
namelen := binary.BigEndian.Uint16(pkt.Data[4+digLen : 6+digLen])
name := pkt.Data[6+digLen : 6+digLen+namelen]
cache := pkt.Data[6+digLen+namelen] == uint8(1)
data := pkt.Data[11+digLen+namelen:]
digLenBytes := make([]byte, 2)
r.Read(digLenBytes)
digLen := binary.BigEndian.Uint16(digLenBytes)
digest := make([]byte, digLen)
r.Read(digest)
namelenBytes := make([]byte, 2)
r.Read(namelenBytes)
namelen := binary.BigEndian.Uint16(namelenBytes)
name := make([]byte, namelen)
r.Read(name)
cacheByte, _ := r.ReadByte()
cache := cacheByte == uint8(1)
r.Seek(5, io.SeekCurrent)
data := make([]byte, r.Len())
r.Read(data)
media[string(name)] = &mediaFile{
digest: digest,
@ -248,8 +354,8 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
noCache: !cache,
}
for _, peer := range Peers() {
ack, err := peer.Send(*pkt)
for _, conn := range Conns() {
ack, err := conn.Send(*pkt)
if err != nil {
log.Print(err)
}
@ -263,7 +369,7 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
return false
}
} else {
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
switch cmd := binary.BigEndian.Uint16(cmdBytes); cmd {
case ToServerChatMessage:
return processChatMessage(src, *pkt)
case ToServerFirstSrp:
@ -271,11 +377,19 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
src.sudoMode = false
// This is a password change, save verifier and salt
lenS := binary.BigEndian.Uint16(pkt.Data[2:4])
s := pkt.Data[4 : 4+lenS]
lenSBytes := make([]byte, 2)
r.Read(lenSBytes)
lenS := binary.BigEndian.Uint16(lenSBytes)
lenV := binary.BigEndian.Uint16(pkt.Data[4+lenS : 6+lenS])
v := pkt.Data[6+lenS : 6+lenS+lenV]
s := make([]byte, lenS)
r.Read(s)
lenVBytes := make([]byte, 2)
r.Read(lenVBytes)
lenV := binary.BigEndian.Uint16(lenVBytes)
v := make([]byte, lenV)
r.Read(v)
pwd := encodeVerifierAndSalt(s, v)
@ -295,11 +409,16 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
} else {
log.Print("User " + src.Username() + " at " + src.Addr().String() + " did not enter sudo mode before attempting to change the password")
}
return true
case ToServerSrpBytesA:
if !src.sudoMode {
lenA := binary.BigEndian.Uint16(pkt.Data[2:4])
A := pkt.Data[4 : 4+lenA]
lenABytes := make([]byte, 2)
r.Read(lenABytes)
lenA := binary.BigEndian.Uint16(lenABytes)
A := make([]byte, lenA)
r.Read(A)
db, err := initAuthDB()
if err != nil {
@ -341,7 +460,7 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
binary.BigEndian.PutUint16(data[4+len(s):6+len(s)], uint16(len(B)))
copy(data[6+len(s):6+len(s)+len(B)], B)
ack, err := src.Send(rudp.Pkt{Data: data})
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
return true
@ -351,8 +470,12 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
return true
case ToServerSrpBytesM:
if !src.sudoMode {
lenM := binary.BigEndian.Uint16(pkt.Data[2:4])
M := pkt.Data[4 : 4+lenM]
lenMBytes := make([]byte, 2)
r.Read(lenMBytes)
lenM := binary.BigEndian.Uint16(lenMBytes)
M := make([]byte, lenM)
r.Read(M)
M2 := srp.CalculateM([]byte(src.Username()), src.srp_s, src.srp_A, src.srp_B, src.srp_K)
@ -364,7 +487,7 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
// Send ACCEPT_SUDO_MODE
data := []byte{0, ToClientAcceptSudoMode}
ack, err := src.Send(rudp.Pkt{Data: data})
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
return true
@ -377,7 +500,7 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
// Send DENY_SUDO_MODE
data := []byte{0, ToClientDenySudoMode}
ack, err := src.Send(rudp.Pkt{Data: data})
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
return true
@ -395,7 +518,7 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
binary.BigEndian.PutUint16(data[3:5], uint16(len(rpcCh)))
copy(data[5:], []byte(rpcCh))
ack, err := src.Send(rudp.Pkt{Data: data})
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
@ -408,7 +531,11 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
return true
}
ch := string(pkt.Data[4:])
r.Seek(2, io.SeekCurrent)
chBytes := make([]byte, r.Len())
r.Read(chBytes)
ch := string(chBytes)
if ch == rpcCh {
deny()
return true
@ -425,7 +552,7 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
binary.BigEndian.PutUint16(data[3:5], uint16(len(rpcCh)))
copy(data[5:], []byte(rpcCh))
ack, err := src.Send(rudp.Pkt{Data: data})
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
@ -438,7 +565,11 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
return true
}
ch := string(pkt.Data[4:])
r.Seek(2, io.SeekCurrent)
chBytes := make([]byte, r.Len())
r.Read(chBytes)
ch := string(chBytes)
if ch == rpcCh {
deny()
return true
@ -452,8 +583,13 @@ func processPktCommand(src, dst *Peer, pkt *rudp.Pkt) bool {
return true
}
chlen := binary.BigEndian.Uint16(pkt.Data[2:4])
ch := string(pkt.Data[4 : 4+chlen])
chlenBytes := make([]byte, 2)
r.Read(chlenBytes)
chlen := binary.BigEndian.Uint16(chlenBytes)
chBytes := make([]byte, chlen)
r.Read(chBytes)
ch := string(chBytes)
if ch == rpcCh {
return true
}

171
conn.go Normal file
View File

@ -0,0 +1,171 @@
package main
import (
"bytes"
"fmt"
"net"
"sync"
"time"
"github.com/anon55555/mt"
"github.com/anon55555/mt/rudp"
)
var connectedConns int = 0
var connectedConnsMu sync.RWMutex
// A Conn is a connection to a client or server
type Conn struct {
*rudp.Conn
protoVer uint16
username string
srp_s []byte
srp_A []byte
srp_a []byte
srp_B []byte
srp_K []byte
authMech int
sudoMode bool
stopforward bool
forwardMu sync.RWMutex
redirectMu sync.Mutex
srvMu sync.RWMutex
srv *Conn
initAoReceived bool
aoIDs map[uint16]bool
localPlayerCao uint16
currentPlayerCao uint16
useRpcMu sync.RWMutex
useRpc bool
noClt bool
modChs map[string]bool
huds map[uint32]bool
sounds map[int32]bool
blocks [][3]int16
inv *mt.Inv
}
// ProtoVer returns the protocol version of the Conn
func (c *Conn) ProtoVer() uint16 { return c.protoVer }
// Addr returns the remote address of the Conn
func (c *Conn) Addr() net.Addr {
return c.Conn.RemoteAddr()
}
// Username returns the username of the Conn
// if it isn't a server
func (c *Conn) Username() string { return c.username }
// Forward reports whether the Proxy func should continue or stop
func (c *Conn) Forward() bool {
c.forwardMu.RLock()
defer c.forwardMu.RUnlock()
return !c.stopforward
}
// stopForwarding tells the Proxy func to stop
func (c *Conn) stopForwarding() {
c.forwardMu.Lock()
defer c.forwardMu.Unlock()
c.stopforward = true
}
// Server returns the Conn this Conn is connected to
// if it isn't a server
func (c *Conn) Server() *Conn {
c.srvMu.RLock()
defer c.srvMu.RUnlock()
return c.srv
}
// ServerName returns the name of the Conn this Conn is connected to
// if this Conn is not a server
func (c *Conn) ServerName() string {
servers := ConfKey("servers").(map[interface{}]interface{})
for server := range servers {
if ConfKey("servers:"+server.(string)+":address") == c.Server().Addr().String() {
return server.(string)
}
}
return ""
}
// SetServer sets the Conn this Conn is connected to
// if this Conn is not a server
func (c *Conn) SetServer(s *Conn) {
c.srvMu.Lock()
defer c.srvMu.Unlock()
c.srv = s
}
// UseRpc reports whether RPC messages can be sent to the Conn
func (c *Conn) UseRpc() bool {
c.useRpcMu.RLock()
defer c.useRpcMu.RUnlock()
return c.useRpc
}
// SetUseRpc sets the value returned by UseRpc
func (c *Conn) SetUseRpc(useRpc bool) {
c.useRpcMu.Lock()
defer c.useRpcMu.Unlock()
c.useRpc = useRpc
}
// NoClt reports whether the Conn is RPC-only
func (c *Conn) NoClt() bool { return c.noClt }
// MakeRpcOnly marks the Conn as RPC-only
func (c *Conn) MakeRpcOnly() {
c.noClt = true
}
// Inv returns the inventory of the Conn
func (c *Conn) Inv() *mt.Inv { return c.inv }
// Connect connects to the server on conn
// and closes conn when the Conn disconnects
func Connect(conn net.Conn) (*Conn, error) {
srv := &Conn{Conn: rudp.Connect(conn)}
ack, err := srv.Send(rudp.Pkt{Reader: bytes.NewReader([]byte{0, 0})})
if err != nil {
return nil, err
}
select {
case <-time.After(8 * time.Second):
srv.Close()
return nil, fmt.Errorf("server at %s is unreachable", conn.RemoteAddr().String())
case <-ack:
}
return srv, nil
}
// ConnCount reports how many client Conns are connected
func ConnCount() int {
connectedConnsMu.RLock()
defer connectedConnsMu.RUnlock()
return connectedConns
}

9
end.go
View File

@ -1,6 +1,7 @@
package main
import (
"bytes"
"log"
"os"
"time"
@ -29,19 +30,19 @@ func End(crash, reconnect bool) {
}
data[6] = uint8(0x00)
for _, clt := range Peers() {
_, err := clt.Send(rudp.Pkt{Data: data})
r := bytes.NewReader(data)
for _, clt := range Conns() {
_, err := clt.Send(rudp.Pkt{Reader: r})
if err != nil {
log.Print(err)
}
clt.SendDisco(0, true)
clt.Close()
}
rpcSrvMu.Lock()
for srv := range rpcSrvs {
srv.SendDisco(0, true)
srv.Close()
}
rpcSrvMu.Unlock()

2
go.mod
View File

@ -4,7 +4,7 @@ go 1.16
require (
github.com/HimbeerserverDE/srp v0.0.0-20210220165753-1b954ef7b017
github.com/anon55555/mt v0.0.0-20210303173846-1bae1f4f7ea3
github.com/anon55555/mt v0.0.0-20210322183736-433955e45ef3
github.com/mattn/go-sqlite3 v1.14.6
gopkg.in/yaml.v2 v2.4.0
)

4
go.sum
View File

@ -1,7 +1,7 @@
github.com/HimbeerserverDE/srp v0.0.0-20210220165753-1b954ef7b017 h1:0vIYOfwAd3MtssbclXpCuUHVVV+5VOH0H1ld9+zSxgM=
github.com/HimbeerserverDE/srp v0.0.0-20210220165753-1b954ef7b017/go.mod h1:pxNH8S2nh4n2DWE0ToX5GnnDr/uEAuaAhJsCpkDLIWw=
github.com/anon55555/mt v0.0.0-20210303173846-1bae1f4f7ea3 h1:oXXIHh5R80MlxHRWuzNphK1/E5EcUuWNv+a2GL+08f4=
github.com/anon55555/mt v0.0.0-20210303173846-1bae1f4f7ea3/go.mod h1:jH4ER+ahjl7H6TczzK+q4V9sXY++U2Geh6/vt3r4Xvs=
github.com/anon55555/mt v0.0.0-20210322183736-433955e45ef3 h1:hTmpFbZdelNmvmKQDsfk+a7vzpLpvtLR5nyzMYI9Xyc=
github.com/anon55555/mt v0.0.0-20210322183736-433955e45ef3/go.mod h1:jH4ER+ahjl7H6TczzK+q4V9sXY++U2Geh6/vt3r4Xvs=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

16
hand.go
View File

@ -6,26 +6,26 @@ import (
"github.com/anon55555/mt"
)
func (p *Peer) UpdateHandCapabs() error {
l := p.Inv().List("hand")
func (c *Conn) UpdateHandCapabs() error {
l := c.Inv().List("hand")
if l == nil {
*p.inv = mt.Inv(append([]mt.NamedInvList(*p.inv), mt.NamedInvList{
*c.inv = mt.Inv(append([]mt.NamedInvList(*c.inv), mt.NamedInvList{
Name: "hand",
InvList: mt.InvList{
Width: 1,
},
}))
l = p.Inv().List("hand")
l = c.Inv().List("hand")
}
var hand mt.Stack
if len(l.Stacks) == 1 && l.Stacks[0].Name != "multiserver:hand_"+p.ServerName() {
if len(l.Stacks) == 1 && l.Stacks[0].Name != "multiserver:hand_"+c.ServerName() {
hand = l.Stacks[0]
caps := handcapabs[p.ServerName()]
caps := handcapabs[c.ServerName()]
if caps == nil {
return fmt.Errorf("hand tool capabilities of server %s missing", p.ServerName())
return fmt.Errorf("hand tool capabilities of server %s missing", c.ServerName())
}
s, err := caps.SerializeJSON()
@ -37,7 +37,7 @@ func (p *Peer) UpdateHandCapabs() error {
} else {
hand = mt.Stack{
Item: mt.Item{
Name: "multiserver:hand_" + p.ServerName(),
Name: "multiserver:hand_" + c.ServerName(),
},
Count: 1,
}

View File

@ -22,18 +22,18 @@ func init() {
RegisterChatCommand("help",
nil,
"Shows the help for a command. Shows the help for all commands if executed without arguments. Usage: help [command]",
func(p *Peer, param string) {
func(c *Conn, param string) {
showHelp := func(name string) {
cmd := chatCommands[name]
if help := cmd.Help(); help != "" {
color := "#F00"
if has, err := p.CheckPrivs(cmd.privs); (err == nil && has) || cmd.privs == nil {
if has, err := c.CheckPrivs(cmd.privs); (err == nil && has) || cmd.privs == nil {
color = "#0F0"
}
p.SendChatMsg(Colorize(name, color) + ": " + help)
c.SendChatMsg(Colorize(name, color) + ": " + help)
} else {
p.SendChatMsg("No help available for " + name + ".")
c.SendChatMsg("No help available for " + name + ".")
}
}
@ -49,68 +49,68 @@ func init() {
RegisterChatCommand("send",
privs("send"),
"Sends a player to a server. Usage: send <playername> <servername>",
func(p *Peer, param string) {
func(c *Conn, param string) {
if param == "" {
p.SendChatMsg("Usage: send <playername> <servername>")
c.SendChatMsg("Usage: send <playername> <servername>")
return
}
name := strings.Split(param, " ")[0]
if name == "" || len(strings.Split(param, " ")) < 2 {
p.SendChatMsg("Usage: send <playername> <servername>")
c.SendChatMsg("Usage: send <playername> <servername>")
return
}
tosrv := strings.Split(param, " ")[1]
if tosrv == "" {
p.SendChatMsg("Usage: send <playername> <servername>")
c.SendChatMsg("Usage: send <playername> <servername>")
return
}
servers := ConfKey("servers").(map[interface{}]interface{})
if servers[tosrv] == nil {
p.SendChatMsg("Unknown servername " + tosrv)
c.SendChatMsg("Unknown servername " + tosrv)
return
}
p2 := PeerByUsername(name)
if p2 == nil {
p.SendChatMsg(name + " is not online.")
c2 := ConnByUsername(name)
if c2 == nil {
c.SendChatMsg(name + " is not online.")
return
}
srv := p2.ServerName()
srv := c2.ServerName()
if srv == tosrv {
p.SendChatMsg(name + " is already connected to this server!")
c.SendChatMsg(name + " is already connected to this server!")
}
go p2.Redirect(tosrv)
go c2.Redirect(tosrv)
})
RegisterChatCommand("sendcurrent",
privs("send"),
"Sends all players on the current server to a new server. Usage: sendcurrent <servername>",
func(p *Peer, param string) {
func(c *Conn, param string) {
if param == "" {
p.SendChatMsg("Usage: sendcurrent <servername>")
c.SendChatMsg("Usage: sendcurrent <servername>")
return
}
servers := ConfKey("servers").(map[interface{}]interface{})
if servers[param] == nil {
p.SendChatMsg("Unknown servername " + param)
c.SendChatMsg("Unknown servername " + param)
return
}
srv := p.ServerName()
srv := c.ServerName()
if srv == param {
p.SendChatMsg("All targets are already connected to this server!")
c.SendChatMsg("All targets are already connected to this server!")
return
}
go func() {
for _, p := range Peers() {
if p.ServerName() == srv {
p.Redirect(param)
for _, c := range Conns() {
if c.ServerName() == srv {
c.Redirect(param)
}
}
}()
@ -119,22 +119,22 @@ func init() {
RegisterChatCommand("sendall",
privs("send"),
"Sends all players to a server. Usage: sendall <servername>",
func(p *Peer, param string) {
func(c *Conn, param string) {
if param == "" {
p.SendChatMsg("Usage: sendall <servername>")
c.SendChatMsg("Usage: sendall <servername>")
return
}
servers := ConfKey("servers").(map[interface{}]interface{})
if servers[param] == nil {
p.SendChatMsg("Unknown servername " + param)
c.SendChatMsg("Unknown servername " + param)
return
}
go func() {
for _, p := range Peers() {
if psrv := p.ServerName(); psrv != param {
p.Redirect(param)
for _, c := range Conns() {
if psrv := c.ServerName(); psrv != param {
c.Redirect(param)
}
}
}()
@ -143,7 +143,7 @@ func init() {
RegisterChatCommand("alert",
privs("alert"),
"Sends a message to all players that are connected to the network. Usage: alert [message]",
func(p *Peer, param string) {
func(c *Conn, param string) {
ChatSendAll("[ALERT] " + param)
})
@ -151,26 +151,26 @@ func init() {
nil,
`Prints your current server and a list of all servers if executed without arguments.
Sends you to a server if executed with arguments and the required privilege. Usage: server [servername]"`,
func(p *Peer, param string) {
func(c *Conn, param string) {
if param == "" {
var r string
servers := ConfKey("servers").(map[interface{}]interface{})
for server := range servers {
r += server.(string) + " "
}
srv := p.ServerName()
p.SendChatMsg("Current server: " + srv + " | All servers: " + r)
c.SendChatMsg("Current server: " + c.ServerName() + " | All servers: " + r)
} else {
servers := ConfKey("servers").(map[interface{}]interface{})
srv := p.ServerName()
srv := c.ServerName()
if srv == param {
p.SendChatMsg("You are already connected to this server!")
c.SendChatMsg("You are already connected to this server!")
return
}
if servers[param] == nil {
p.SendChatMsg("Unknown servername " + param)
c.SendChatMsg("Unknown servername " + param)
return
}
@ -180,62 +180,62 @@ func init() {
reqprivs[reqpriv] = true
}
allow, err := p.CheckPrivs(reqprivs)
allow, err := c.CheckPrivs(reqprivs)
if err != nil {
log.Print(err)
p.SendChatMsg("An internal error occured while attempting to check your privileges.")
c.SendChatMsg("An internal error occured while attempting to check your privileges.")
return
}
if !allow {
p.SendChatMsg("You do not have permission to join this server! Required privilege: " + reqpriv)
c.SendChatMsg("You do not have permission to join this server! Required privilege: " + reqpriv)
return
}
go p.Redirect(param)
p.SendChatMsg("Redirecting you to " + param + ".")
go c.Redirect(param)
c.SendChatMsg("Redirecting you to " + param + ".")
}
})
RegisterChatCommand("find",
privs("find"),
"Prints the online status and the current server of a player. Usage: find <playername>",
func(p *Peer, param string) {
func(c *Conn, param string) {
if param == "" {
p.SendChatMsg("Usage: find <playername>")
c.SendChatMsg("Usage: find <playername>")
return
}
p2 := PeerByUsername(param)
if p2 == nil {
p.SendChatMsg(param + " is not online.")
c2 := ConnByUsername(param)
if c2 == nil {
c.SendChatMsg(param + " is not online.")
} else {
srv := p2.ServerName()
p.SendChatMsg(param + " is connected to server " + srv + ".")
srv := c2.ServerName()
c.SendChatMsg(param + " is connected to server " + srv + ".")
}
})
RegisterChatCommand("addr",
privs("addr"),
"Prints the network address (including the port) of a connected player. Usage: addr <playername>",
func(p *Peer, param string) {
func(c *Conn, param string) {
if param == "" {
p.SendChatMsg("Usage: addr <playername>")
c.SendChatMsg("Usage: addr <playername>")
return
}
p2 := PeerByUsername(param)
if p2 == nil {
p.SendChatMsg(param + " is not online.")
c2 := ConnByUsername(param)
if c2 == nil {
c.SendChatMsg(param + " is not online.")
} else {
p.SendChatMsg(param + "'s address is " + p2.Addr().String())
c.SendChatMsg(param + "'s address is " + c2.Addr().String())
}
})
RegisterChatCommand("end",
privs("end"),
"Kicks all connected clients and stops the proxy. Usage: end",
func(p *Peer, param string) {
func(c *Conn, param string) {
go End(false, false)
})
@ -243,12 +243,12 @@ func init() {
nil,
`Prints your privileges if executed without arguments.
Prints a connected player's privileges if executed with arguments. Usage: privs [playername]`,
func(p *Peer, param string) {
func(c *Conn, param string) {
var r string
name := param
if name == "" {
name = p.Username()
name = c.Username()
r += "Your privileges: "
} else {
r += name + "'s privileges: "
@ -257,26 +257,26 @@ func init() {
privs, err := Privs(name)
if err != nil {
log.Print(err)
p.SendChatMsg("An internal error occured while attempting to get the privileges.")
c.SendChatMsg("An internal error occured while attempting to get the privileges.")
return
}
eprivs := encodePrivs(privs)
p.SendChatMsg(r + strings.Replace(eprivs, "|", " ", -1))
c.SendChatMsg(r + strings.Replace(eprivs, "|", " ", -1))
})
RegisterChatCommand("grant",
privs("privs"),
`Grants privileges to a connected player. The privileges need to be comma-seperated.
If the playername is omitted, privileges are granted to you. Usage: grant [playername] <privileges>`,
func(p *Peer, param string) {
func(c *Conn, param string) {
name := strings.Split(param, " ")[0]
var privnames string
if len(strings.Split(param, " ")) < 2 {
privnames = name
name = p.Username()
name = c.Username()
} else {
privnames = strings.Split(param, " ")[1]
}
@ -284,7 +284,7 @@ func init() {
privs, err := Privs(name)
if err != nil {
log.Print(err)
p.SendChatMsg("An internal error occured while attempting to get the privileges.")
c.SendChatMsg("An internal error occured while attempting to get the privileges.")
return
}
@ -296,24 +296,24 @@ func init() {
err = SetPrivs(name, privs)
if err != nil {
log.Print(err)
p.SendChatMsg("An internal error occured while attempting to set the privileges.")
c.SendChatMsg("An internal error occured while attempting to set the privileges.")
return
}
p.SendChatMsg("Privileges updated.")
c.SendChatMsg("Privileges updated.")
})
RegisterChatCommand("revoke",
privs("privs"),
`Revokes privileges from a connected player. The privileges need to be comma-seperated.
If the playername is omitted, privileges are revoked from you. Usage: revoke [playername] <privileges>`,
func(p *Peer, param string) {
func(c *Conn, param string) {
name := strings.Split(param, " ")[0]
var privnames string
if len(strings.Split(param, " ")) < 2 {
privnames = name
name = p.Username()
name = c.Username()
} else {
privnames = strings.Split(param, " ")[1]
}
@ -321,7 +321,7 @@ func init() {
privs, err := Privs(name)
if err != nil {
log.Print(err)
p.SendChatMsg("An internal error occured while attempting to get the privileges.")
c.SendChatMsg("An internal error occured while attempting to get the privileges.")
return
}
@ -333,20 +333,20 @@ func init() {
err = SetPrivs(name, privs)
if err != nil {
log.Print(err)
p.SendChatMsg("An internal error occured while attempting to set the privileges.")
c.SendChatMsg("An internal error occured while attempting to set the privileges.")
return
}
p.SendChatMsg("Privileges updated.")
c.SendChatMsg("Privileges updated.")
})
RegisterChatCommand("banlist",
privs("ban"),
"Prints the list of banned IP address and associated players. Usage: banlist",
func(p *Peer, param string) {
func(c *Conn, param string) {
bans, err := BanList()
if err != nil {
p.SendChatMsg("An internal error occured while attempting to read the ban list.")
c.SendChatMsg("An internal error occured while attempting to read the ban list.")
return
}
@ -355,61 +355,61 @@ func init() {
msg += addr + " | " + name + "\n"
}
p.SendChatMsg(msg)
c.SendChatMsg(msg)
})
RegisterChatCommand("ban",
privs("ban"),
"Bans an IP address or a connected player. Usage: ban <playername | IP address>",
func(p *Peer, param string) {
func(c *Conn, param string) {
if param == "" {
p.SendChatMsg("Usage: ban <playername | IP address>")
c.SendChatMsg("Usage: ban <playername | IP address>")
return
}
err := Ban(param)
if err != nil {
p2 := PeerByUsername(param)
if p2 == nil {
p.SendChatMsg(param + " is not online.")
c2 := ConnByUsername(param)
if c2 == nil {
c.SendChatMsg(param + " is not online.")
return
}
if err := p2.Ban(); err != nil {
p.SendChatMsg("An internal error occured while attempting to ban the player.")
if err := c2.Ban(); err != nil {
c.SendChatMsg("An internal error occured while attempting to ban the player.")
return
}
}
p.SendChatMsg("Banned " + param)
c.SendChatMsg("Banned " + param)
})
RegisterChatCommand("unban",
privs("ban"),
"Unbans an IP address or a playername. Usage: unban <playername | IP address>",
func(p *Peer, param string) {
func(c *Conn, param string) {
if param == "" {
p.SendChatMsg("Usage: unban <playername | IP address>")
c.SendChatMsg("Usage: unban <playername | IP address>")
return
}
if err := Unban(param); err != nil {
p.SendChatMsg("An internal error occured while attempting to unban the player.")
c.SendChatMsg("An internal error occured while attempting to unban the player.")
return
}
p.SendChatMsg("Unbanned " + param)
c.SendChatMsg("Unbanned " + param)
})
RegisterOnRedirectDone(func(p *Peer, newsrv string, success bool) {
RegisterOnRedirectDone(func(c *Conn, newsrv string, success bool) {
if success {
err := SetStorageKey("server:"+p.Username(), newsrv)
err := SetStorageKey("server:"+c.Username(), newsrv)
if err != nil {
log.Print(err)
return
}
} else {
p.SendChatMsg("Could not connect you to " + newsrv + "!")
c.SendChatMsg("Could not connect you to " + newsrv + "!")
}
})

376
init.go
View File

@ -1,9 +1,11 @@
package main
import (
"bytes"
"crypto/subtle"
"encoding/binary"
"errors"
"io"
"log"
"net"
"strings"
@ -15,37 +17,43 @@ import (
// Init authenticates to the server srv
// and finishes the initialisation process if ignMedia is true
func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
func Init(c, c2 *Conn, ignMedia, noAccessDenied bool, fin chan *Conn) {
defer close(fin)
if p2.IsSrv() {
if c2.IsSrv() {
// We're trying to connect to a server
// INIT
data := make([]byte, 11+len(p.Username()))
data := make([]byte, 11+len(c.Username()))
data[0] = uint8(0x00)
data[1] = uint8(ToServerInit)
data[2] = uint8(0x1c)
binary.BigEndian.PutUint16(data[3:5], uint16(0x0000))
binary.BigEndian.PutUint16(data[5:7], uint16(ProtoMin))
binary.BigEndian.PutUint16(data[7:9], uint16(ProtoLatest))
binary.BigEndian.PutUint16(data[9:11], uint16(len(p.Username())))
copy(data[11:], []byte(p.Username()))
binary.BigEndian.PutUint16(data[9:11], uint16(len(c.Username())))
copy(data[11:], []byte(c.Username()))
time.Sleep(250 * time.Millisecond)
if _, err := p2.Send(rudp.Pkt{Data: data, ChNo: 1, Unrel: true}); err != nil {
if _, err := c2.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
Unrel: true,
},
}); err != nil {
log.Print(err)
}
for {
pkt, err := p2.Recv()
pkt, err := c2.Recv()
if err != nil {
if errors.Is(err, net.ErrClosed) {
msg := p2.Addr().String() + " disconnected"
if p2.TimedOut() {
msg += " (timed out)"
if err = c2.WhyClosed(); err != nil {
log.Print(c2.Addr().String(), " disconnected with error: ", err)
} else {
log.Print(c2.Addr().String(), " disconnected")
}
log.Print(msg)
return
}
@ -54,13 +62,25 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
continue
}
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
case ToClientHello:
p2.protoVer = binary.BigEndian.Uint16(pkt.Data[5:7])
r := ByteReader(pkt)
if pkt.Data[10]&AuthMechSRP > 0 {
cmdBytes := make([]byte, 2)
r.Read(cmdBytes)
switch cmd := binary.BigEndian.Uint16(cmdBytes); cmd {
case ToClientHello:
r.Seek(5, io.SeekStart)
protoVerBytes := make([]byte, 2)
r.Read(protoVerBytes)
c2.protoVer = binary.BigEndian.Uint16(protoVerBytes)
r.Seek(10, io.SeekStart)
authMechByte, _ := r.ReadByte()
if authMechByte&AuthMechSRP > 0 {
// Compute and send SRP_BYTES_A
_, _, err := srp.NewClient([]byte(strings.ToLower(p.Username())), passPhrase)
_, _, err := srp.NewClient([]byte(strings.ToLower(c.Username())), passPhrase)
if err != nil {
log.Print(err)
continue
@ -72,17 +92,23 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
continue
}
p.srp_A = A
p.srp_a = a
c.srp_A = A
c.srp_a = a
data := make([]byte, 5+len(p.srp_A))
data := make([]byte, 5+len(c.srp_A))
data[0] = uint8(0x00)
data[1] = uint8(ToServerSrpBytesA)
binary.BigEndian.PutUint16(data[2:4], uint16(len(p.srp_A)))
copy(data[4:4+len(p.srp_A)], p.srp_A)
data[4+len(p.srp_A)] = uint8(1)
binary.BigEndian.PutUint16(data[2:4], uint16(len(c.srp_A)))
copy(data[4:4+len(c.srp_A)], c.srp_A)
data[4+len(c.srp_A)] = uint8(1)
ack, err := c2.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
ack, err := p2.Send(rudp.Pkt{Data: data, ChNo: 1})
if err != nil {
log.Print(err)
continue
@ -90,7 +116,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
<-ack
} else {
// Compute and send s and v
s, v, err := srp.NewClient([]byte(strings.ToLower(p.Username())), passPhrase)
s, v, err := srp.NewClient([]byte(strings.ToLower(c.Username())), passPhrase)
if err != nil {
log.Print(err)
continue
@ -105,7 +131,13 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
copy(data[6+len(s):6+len(s)+len(v)], v)
data[6+len(s)+len(v)] = uint8(0)
ack, err := p2.Send(rudp.Pkt{Data: data, ChNo: 1})
ack, err := c2.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
@ -114,19 +146,27 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
}
case ToClientSrpBytesSB:
// Compute and send SRP_BYTES_M
lenS := binary.BigEndian.Uint16(pkt.Data[2:4])
s := pkt.Data[4 : lenS+4]
B := pkt.Data[lenS+6:]
lenSBytes := make([]byte, 2)
r.Read(lenSBytes)
lenS := binary.BigEndian.Uint16(lenSBytes)
K, err := srp.CompleteHandshake(p.srp_A, p.srp_a, []byte(strings.ToLower(p.Username())), passPhrase, s, B)
s := make([]byte, lenS)
r.Read(s)
r.Seek(2, io.SeekCurrent)
B := make([]byte, r.Len())
r.Read(B)
K, err := srp.CompleteHandshake(c.srp_A, c.srp_a, []byte(strings.ToLower(c.Username())), passPhrase, s, B)
if err != nil {
log.Print(err)
continue
}
p.srp_K = K
c.srp_K = K
M := srp.CalculateM([]byte(p.Username()), s, p.srp_A, B, p.srp_K)
M := srp.CalculateM([]byte(c.Username()), s, c.srp_A, B, c.srp_K)
data := make([]byte, 4+len(M))
data[0] = uint8(0x00)
@ -134,7 +174,13 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
binary.BigEndian.PutUint16(data[2:4], uint16(len(M)))
copy(data[4:], M)
ack, err := p2.Send(rudp.Pkt{Data: data, ChNo: 1})
ack, err := c2.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
@ -145,7 +191,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
servers := ConfKey("servers").(map[interface{}]interface{})
var srv string
for server := range servers {
if ConfKey("servers:"+server.(string)+":address") == p2.Addr().String() {
if ConfKey("servers:"+server.(string)+":address") == c2.Addr().String() {
srv = server.(string)
break
}
@ -162,22 +208,27 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
AccessDeniedServerFail, 0, 0, 0, 0,
}
ack, err := p.Send(rudp.Pkt{Data: data})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
<-ack
p.SendDisco(0, true)
p.Close()
c.Close()
return
case ToClientAuthAccept:
// Auth succeeded
defer func() {
fin <- p2
fin <- c2
}()
ack, err := p2.Send(rudp.Pkt{Data: []byte{0, ToServerInit2, 0, 0}, ChNo: 1})
ack, err := c2.Send(rudp.Pkt{
Reader: bytes.NewReader([]byte{0, ToServerInit2, 0, 0}),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
@ -200,7 +251,13 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
binary.BigEndian.PutUint16(data[6:8], uint16(len(v)))
copy(data[8:], v)
_, err := p2.Send(rudp.Pkt{Data: data, ChNo: 1})
_, err := c2.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
@ -211,20 +268,20 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
}
} else {
for {
pkt, err := p2.Recv()
pkt, err := c2.Recv()
if err != nil {
if errors.Is(err, net.ErrClosed) {
msg := p2.Addr().String() + " disconnected"
if p2.TimedOut() {
msg += " (timed out)"
if err = c2.WhyClosed(); err != nil {
log.Print(c2.Addr().String(), " disconnected with error: ", err)
} else {
log.Print(c2.Addr().String(), " disconnected")
}
log.Print(msg)
connectedPeersMu.Lock()
connectedPeers--
connectedPeersMu.Unlock()
connectedConnsMu.Lock()
connectedConns--
connectedConnsMu.Unlock()
processLeave(p2)
processLeave(c2)
return
}
@ -233,14 +290,30 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
continue
}
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
r := ByteReader(pkt)
cmdBytes := make([]byte, 2)
r.Read(cmdBytes)
switch cmd := binary.BigEndian.Uint16(cmdBytes); cmd {
case ToServerInit:
// Process data
p2.username = string(pkt.Data[11:])
r.Seek(11, io.SeekStart)
usernameBytes := make([]byte, r.Len())
r.Read(usernameBytes)
c2.username = string(usernameBytes)
r.Seek(5, io.SeekStart)
// Find protocol version
cliProtoMin := binary.BigEndian.Uint16(pkt.Data[5:7])
cliProtoMax := binary.BigEndian.Uint16(pkt.Data[7:9])
cliProtoMinBytes := make([]byte, 2)
r.Read(cliProtoMinBytes)
cliProtoMin := binary.BigEndian.Uint16(cliProtoMinBytes)
cliProtoMaxBytes := make([]byte, 2)
r.Read(cliProtoMaxBytes)
cliProtoMax := binary.BigEndian.Uint16(cliProtoMaxBytes)
var protov uint16
if cliProtoMax >= ProtoMin || cliProtoMin <= ProtoLatest {
if cliProtoMax > ProtoLatest {
@ -250,7 +323,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
}
}
p2.protoVer = protov
c2.protoVer = protov
if protov < ProtoMin || protov > ProtoLatest {
data := []byte{
@ -258,20 +331,19 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
AccessDeniedWrongVersion, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
c2.Close()
fin <- c
return
}
// Send HELLO
data := make([]byte, 13+len(p2.Username()))
data := make([]byte, 13+len(c2.Username()))
data[0] = uint8(0x00)
data[1] = uint8(ToClientHello)
data[2] = uint8(0x1c)
@ -279,14 +351,14 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
binary.BigEndian.PutUint16(data[5:7], uint16(protov))
// Check if user is banned
banned, bname, err := p2.IsBanned()
banned, bname, err := c2.IsBanned()
if err != nil {
log.Print(err)
continue
}
if banned {
log.Print("Banned user " + bname + " at " + p2.Addr().String() + " tried to connect")
log.Print("Banned user " + bname + " at " + c2.Addr().String() + " tried to connect")
reason := []byte("Your IP address is banned. Banned name is " + bname)
l := len(reason)
@ -300,55 +372,52 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
data[5+l] = uint8(0x00)
data[6+l] = uint8(0x00)
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
c2.Close()
fin <- c
return
}
// Check if user is already connected
if IsOnline(p2.Username()) {
if IsOnline(c2.Username()) {
data := []byte{
0, ToClientAccessDenied,
AccessDeniedAlreadyConnected, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
c2.Close()
fin <- c
return
}
// Check if username is reserved for media or RPC
if p2.Username() == "media" || p2.Username() == "rpc" {
if c2.Username() == "media" || c2.Username() == "rpc" {
data := []byte{
0, ToClientAccessDenied,
AccessDeniedWrongName, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
c2.Close()
fin <- c
return
}
@ -358,7 +427,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
continue
}
pwd, err := readAuthItem(db, p2.Username())
pwd, err := readAuthItem(db, c2.Username())
if err != nil {
log.Print(err)
continue
@ -368,18 +437,18 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
if pwd == "" {
// New player
p2.authMech = AuthMechFirstSRP
c2.authMech = AuthMechFirstSRP
binary.BigEndian.PutUint32(data[7:11], uint32(AuthMechFirstSRP))
} else {
// Existing player
p2.authMech = AuthMechSRP
c2.authMech = AuthMechSRP
binary.BigEndian.PutUint32(data[7:11], uint32(AuthMechSRP))
}
binary.BigEndian.PutUint16(data[11:13], uint16(len(p2.Username())))
copy(data[13:], []byte(p2.Username()))
binary.BigEndian.PutUint16(data[11:13], uint16(len(c2.Username())))
copy(data[13:], []byte(c2.Username()))
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
@ -388,8 +457,8 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
case ToServerFirstSrp:
// Process data
// Make sure the client is allowed to use AuthMechFirstSRP
if p2.authMech != AuthMechFirstSRP {
log.Print(p2.Addr().String() + " used unsupported AuthMechFirstSRP")
if c2.authMech != AuthMechFirstSRP {
log.Print(c2.Addr().String() + " used unsupported AuthMechFirstSRP")
// Send ACCESS_DENIED
data := []byte{
@ -397,30 +466,39 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
AccessDeniedUnexpectedData, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
c2.Close()
fin <- c
return
}
// This is a new player, save verifier and salt
lenS := binary.BigEndian.Uint16(pkt.Data[2:4])
s := pkt.Data[4 : 4+lenS]
lenSBytes := make([]byte, 2)
r.Read(lenSBytes)
lenS := binary.BigEndian.Uint16(lenSBytes)
lenV := binary.BigEndian.Uint16(pkt.Data[4+lenS : 6+lenS])
v := pkt.Data[6+lenS : 6+lenS+lenV]
s := make([]byte, lenS)
r.Read(s)
lenVBytes := make([]byte, 2)
r.Read(lenVBytes)
lenV := binary.BigEndian.Uint16(lenVBytes)
v := make([]byte, lenV)
r.Read(v)
emptyByte, _ := r.ReadByte()
// Also make sure to check for an empty password
disallow, ok := ConfKey("disallow_empty_passwords").(bool)
if ok && disallow && pkt.Data[6+lenS+lenV] == 1 {
log.Print(p2.Addr().String() + " used an empty password but disallow_empty_passwords is true")
if ok && disallow && emptyByte > 0 {
log.Print(c2.Addr().String() + " used an empty password but disallow_empty_passwords is true")
// Send ACCESS_DENIED
data := []byte{
@ -428,16 +506,15 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
AccessDeniedEmptyPassword, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
c2.Close()
fin <- c
return
}
@ -449,13 +526,13 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
continue
}
err = addAuthItem(db, p2.Username(), pwd)
err = addAuthItem(db, c2.Username(), pwd)
if err != nil {
log.Print(err)
continue
}
err = addPrivItem(db, p2.Username())
err = addPrivItem(db, c2.Username())
if err != nil {
log.Print(err)
continue
@ -479,7 +556,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
0, 0, 0, AuthMechSRP,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
@ -488,8 +565,8 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
case ToServerSrpBytesA:
// Process data
// Make sure the client is allowed to use AuthMechSRP
if p2.authMech != AuthMechSRP {
log.Print(p2.Addr().String() + " used unsupported AuthMechSRP")
if c2.authMech != AuthMechSRP {
log.Print(c2.Addr().String() + " used unsupported AuthMechSRP")
// Send ACCESS_DENIED
data := []byte{
@ -497,20 +574,24 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
AccessDeniedUnexpectedData, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data, ChNo: 0, Unrel: false})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
c2.Close()
return
}
lenA := binary.BigEndian.Uint16(pkt.Data[2:4])
A := pkt.Data[4 : 4+lenA]
lenABytes := make([]byte, 2)
r.Read(lenABytes)
lenA := binary.BigEndian.Uint16(lenABytes)
A := make([]byte, lenA)
r.Read(A)
db, err := initAuthDB()
if err != nil {
@ -518,7 +599,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
continue
}
pwd, err := readAuthItem(db, p2.Username())
pwd, err := readAuthItem(db, c2.Username())
if err != nil {
log.Print(err)
continue
@ -538,10 +619,10 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
continue
}
p2.srp_s = s
p2.srp_A = A
p2.srp_B = B
p2.srp_K = K
c2.srp_s = s
c2.srp_A = A
c2.srp_B = B
c2.srp_K = K
// Send SRP_BYTES_S_B
data := make([]byte, 6+len(s)+len(B))
@ -552,7 +633,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
binary.BigEndian.PutUint16(data[4+len(s):6+len(s)], uint16(len(B)))
copy(data[6+len(s):6+len(s)+len(B)], B)
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
@ -561,8 +642,8 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
case ToServerSrpBytesM:
// Process data
// Make sure the client is allowed to use AuthMechSRP
if p2.authMech != AuthMechSRP {
log.Print(p2.Addr().String() + " used unsupported AuthMechSRP")
if c2.authMech != AuthMechSRP {
log.Print(c2.Addr().String() + " used unsupported AuthMechSRP")
// Send ACCESS_DENIED
data := []byte{
@ -570,23 +651,26 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
AccessDeniedUnexpectedData, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
c2.Close()
fin <- c
return
}
lenM := binary.BigEndian.Uint16(pkt.Data[2:4])
M := pkt.Data[4 : 4+lenM]
lenMBytes := make([]byte, 2)
r.Read(lenMBytes)
lenM := binary.BigEndian.Uint16(lenMBytes)
M2 := srp.CalculateM([]byte(p2.Username()), p2.srp_s, p2.srp_A, p2.srp_B, p2.srp_K)
M := make([]byte, lenM)
r.Read(M)
M2 := srp.CalculateM([]byte(c2.Username()), c2.srp_s, c2.srp_A, c2.srp_B, c2.srp_K)
if subtle.ConstantTimeCompare(M, M2) == 1 {
// Password is correct
@ -606,7 +690,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
0, 0, 0, AuthMechSRP,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
@ -614,7 +698,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
<-ack
} else {
// Client supplied wrong password
log.Print("User " + p2.Username() + " at " + p2.Addr().String() + " supplied wrong password")
log.Print("User " + c2.Username() + " at " + c2.Addr().String() + " supplied wrong password")
// Send ACCESS_DENIED
data := []byte{
@ -622,26 +706,28 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
AccessDeniedWrongPassword, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
c2.Close()
fin <- c
return
}
case ToServerInit2:
p2.announceMedia()
c2.announceMedia()
case ToServerRequestMedia:
p2.sendMedia(pkt.Data[2:])
data := make([]byte, r.Len())
r.Read(data)
c2.sendMedia(data)
case ToServerClientReady:
defaultSrv := ConfKey("default_server").(string)
defSrv := func() *Peer {
defSrv := func() *Conn {
defaultSrvAddr := ConfKey("servers:" + defaultSrv + ":address").(string)
srvaddr, err := net.ResolveUDPAddr("udp", defaultSrvAddr)
@ -656,27 +742,27 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
return nil
}
srv, err := Connect(conn, conn.RemoteAddr())
srv, err := Connect(conn)
if err != nil {
log.Print(err)
return nil
}
fin2 := make(chan *Peer) // close-only
go Init(p2, srv, ignMedia, noAccessDenied, fin2)
fin2 := make(chan *Conn) // close-only
go Init(c2, srv, ignMedia, noAccessDenied, fin2)
<-fin2
go processJoin(p2)
go processJoin(c2)
return srv
}
if forceDefaultServer, ok := ConfKey("force_default_server").(bool); !forceDefaultServer || !ok {
srvname, err := StorageKey("server:" + p2.Username())
srvname, err := StorageKey("server:" + c2.Username())
if err != nil {
srvname, ok = ConfKey("servers:" + ConfKey("default_server").(string) + ":address").(string)
if !ok {
go p2.SendChatMsg("Could not connect you to your last server!")
go c2.SendChatMsg("Could not connect you to your last server!")
fin <- defSrv()
return
@ -685,7 +771,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
straddr, ok := ConfKey("servers:" + srvname + ":address").(string)
if !ok {
go p2.SendChatMsg("Could not connect you to your last server!")
go c2.SendChatMsg("Could not connect you to your last server!")
fin <- defSrv()
return
@ -693,7 +779,7 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
srvaddr, err := net.ResolveUDPAddr("udp", straddr)
if err != nil {
go p2.SendChatMsg("Could not connect you to your last server!")
go c2.SendChatMsg("Could not connect you to your last server!")
fin <- defSrv()
return
@ -701,27 +787,27 @@ func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
conn, err := net.DialUDP("udp", nil, srvaddr)
if err != nil {
go p2.SendChatMsg("Could not connect you to your last server!")
go c2.SendChatMsg("Could not connect you to your last server!")
fin <- defSrv()
return
}
if srvname != defaultSrv {
srv, err := Connect(conn, conn.RemoteAddr())
srv, err := Connect(conn)
if err != nil {
go p2.SendChatMsg("Could not connect you to your last server!")
go c2.SendChatMsg("Could not connect you to your last server!")
fin <- defSrv()
return
}
fin2 := make(chan *Peer) // close-only
go Init(p2, srv, ignMedia, noAccessDenied, fin2)
fin2 := make(chan *Conn) // close-only
go Init(c2, srv, ignMedia, noAccessDenied, fin2)
<-fin2
go p2.updateDetachedInvs(srvname)
go processJoin(p2)
go c2.updateDetachedInvs(srvname)
go processJoin(c2)
fin <- srv
return

View File

@ -1,6 +1,7 @@
package main
import (
"bytes"
"errors"
"net"
"sync"
@ -15,8 +16,8 @@ type Listener struct {
*rudp.Listener
}
var peerMu sync.RWMutex
var peers map[*Peer]struct{}
var connMu sync.RWMutex
var conns map[*Conn]struct{}
func Listen(conn net.PacketConn) *Listener {
return &Listener{
@ -24,27 +25,27 @@ func Listen(conn net.PacketConn) *Listener {
}
}
// Accept waits for and returns a connecting Peer
// Accept waits for and returns a connecting Conn
// You should keep calling this until it returns ErrClosed
// so it doesn't leak a goroutine
func (l *Listener) Accept() (*Peer, error) {
func (l *Listener) Accept() (*Conn, error) {
rp, err := l.Listener.Accept()
if err != nil {
return nil, err
}
clt := &Peer{Peer: rp}
clt := &Conn{Conn: rp}
peerMu.Lock()
peers[clt] = struct{}{}
peerMu.Unlock()
connMu.Lock()
conns[clt] = struct{}{}
connMu.Unlock()
go func() {
<-clt.Disco()
<-clt.Closed()
peerMu.Lock()
delete(peers, clt)
peerMu.Unlock()
connMu.Lock()
delete(conns, clt)
connMu.Unlock()
}()
clt.aoIDs = make(map[uint16]bool)
@ -53,18 +54,18 @@ func (l *Listener) Accept() (*Peer, error) {
clt.sounds = make(map[int32]bool)
clt.inv = &mt.Inv{}
maxPeers, ok := ConfKey("player_limit").(int)
maxConns, ok := ConfKey("player_limit").(int)
if !ok {
maxPeers = int(^uint(0) >> 1)
maxConns = int(^uint(0) >> 1)
}
if PeerCount() >= maxPeers {
if ConnCount() >= maxConns {
data := []byte{
0, ToClientAccessDenied,
AccessDeniedTooManyUsers, 0, 0, 0, 0,
}
_, err := clt.Send(rudp.Pkt{Data: data})
_, err := clt.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return nil, err
}
@ -72,43 +73,43 @@ func (l *Listener) Accept() (*Peer, error) {
return nil, ErrPlayerLimitReached
}
connectedPeersMu.Lock()
connectedPeers++
connectedPeersMu.Unlock()
connectedConnsMu.Lock()
connectedConns++
connectedConnsMu.Unlock()
return clt, nil
}
// PeerByUsername returns the Peer that is using the specified name
// ConnByUsername returns the Conn that is using the specified name
// for authentication
func PeerByUsername(name string) *Peer {
peerMu.RLock()
defer peerMu.RUnlock()
func ConnByUsername(name string) *Conn {
connMu.RLock()
defer connMu.RUnlock()
for p := range peers {
if p.Username() == name {
return p
for c := range conns {
if c.Username() == name {
return c
}
}
return nil
}
// Peers returns an array containing all connected client Peers
func Peers() []*Peer {
peerMu.RLock()
defer peerMu.RUnlock()
// Conns returns an array containing all connected client Conns
func Conns() []*Conn {
connMu.RLock()
defer connMu.RUnlock()
var r []*Peer
for p := range peers {
r = append(r, p)
var r []*Conn
for c := range conns {
r = append(r, c)
}
return r
}
func init() {
peerMu.Lock()
defer peerMu.Unlock()
connMu.Lock()
defer connMu.Unlock()
peers = make(map[*Peer]struct{})
conns = make(map[*Conn]struct{})
}

170
media.go
View File

@ -1,9 +1,11 @@
package main
import (
"bytes"
"encoding/binary"
"encoding/hex"
"errors"
"io"
"log"
"net"
"os"
@ -16,8 +18,6 @@ var media map[string]*mediaFile
var nodedefs map[string][]byte
var itemdefs map[string][]byte
var detachedinvs map[string][][]byte
var movement []byte
var timeofday []byte
type mediaFile struct {
digest []byte
@ -25,13 +25,13 @@ type mediaFile struct {
noCache bool
}
func (p *Peer) fetchMedia() {
if !p.IsSrv() {
func (c *Conn) fetchMedia() {
if !c.IsSrv() {
return
}
for {
pkt, err := p.Recv()
pkt, err := c.Recv()
if err != nil {
if errors.Is(err, net.ErrClosed) {
return
@ -41,57 +41,79 @@ func (p *Peer) fetchMedia() {
continue
}
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
r := ByteReader(pkt)
cmdBytes := make([]byte, 2)
r.Read(cmdBytes)
switch cmd := binary.BigEndian.Uint16(cmdBytes); cmd {
case ToClientNodedef:
servers := ConfKey("servers").(map[interface{}]interface{})
var srvname string
for server := range servers {
if ConfKey("servers:"+server.(string)+":address") == p.Addr().String() {
if ConfKey("servers:"+server.(string)+":address") == c.Addr().String() {
srvname = server.(string)
break
}
}
nodedefs[srvname] = pkt.Data[6:]
r.Seek(6, io.SeekStart)
nodedefs[srvname] = make([]byte, r.Len())
r.Read(nodedefs[srvname])
case ToClientItemdef:
servers := ConfKey("servers").(map[interface{}]interface{})
var srvname string
for server := range servers {
if ConfKey("servers:"+server.(string)+":address") == p.Addr().String() {
if ConfKey("servers:"+server.(string)+":address") == c.Addr().String() {
srvname = server.(string)
break
}
}
itemdefs[srvname] = pkt.Data[6:]
case ToClientMovement:
movement = pkt.Data[2:]
r.Seek(6, io.SeekStart)
itemdefs[srvname] = make([]byte, r.Len())
r.Read(itemdefs[srvname])
case ToClientDetachedInventory:
servers := ConfKey("servers").(map[interface{}]interface{})
var srvname string
for server := range servers {
if ConfKey("servers:"+server.(string)+":address") == p.Addr().String() {
if ConfKey("servers:"+server.(string)+":address") == c.Addr().String() {
srvname = server.(string)
break
}
}
detachedinvs[srvname] = append(detachedinvs[srvname], pkt.Data[2:])
case ToClientTimeOfDay:
timeofday = pkt.Data[2:]
inv := make([]byte, r.Len())
r.Read(inv)
detachedinvs[srvname] = append(detachedinvs[srvname], inv)
case ToClientAnnounceMedia:
var rq []string
count := binary.BigEndian.Uint16(pkt.Data[2:4])
si := uint32(4)
countBytes := make([]byte, 2)
r.Read(countBytes)
count := binary.BigEndian.Uint16(countBytes)
for i := uint16(0); i < count; i++ {
namelen := binary.BigEndian.Uint16(pkt.Data[si : 2+si])
name := pkt.Data[2+si : 2+si+uint32(namelen)]
diglen := binary.BigEndian.Uint16(pkt.Data[2+si+uint32(namelen) : 4+si+uint32(namelen)])
digest := pkt.Data[4+si+uint32(namelen) : 4+si+uint32(namelen)+uint32(diglen)]
namelenBytes := make([]byte, 2)
r.Read(namelenBytes)
namelen := binary.BigEndian.Uint16(namelenBytes)
name := make([]byte, namelen)
r.Read(name)
diglenBytes := make([]byte, 2)
r.Read(diglenBytes)
diglen := binary.BigEndian.Uint16(diglenBytes)
digest := make([]byte, diglen)
r.Read(digest)
if media[string(name)] == nil && !isCached(string(name), digest) {
rq = append(rq, string(name))
media[string(name)] = &mediaFile{digest: digest}
}
si += 4 + uint32(namelen) + uint32(diglen)
}
// Request the media
@ -111,46 +133,66 @@ func (p *Peer) fetchMedia() {
sj += 2 + len(rq[f])
}
_, err := p.Send(rudp.Pkt{Data: data, ChNo: 1})
_, err := c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
}
case ToClientMedia:
bunchcount := binary.BigEndian.Uint16(pkt.Data[2:4])
bunch := binary.BigEndian.Uint16(pkt.Data[4:6])
filecount := binary.BigEndian.Uint32(pkt.Data[6:10])
si := uint32(10)
bunchcountBytes := make([]byte, 2)
r.Read(bunchcountBytes)
bunchcount := binary.BigEndian.Uint16(bunchcountBytes)
bunchBytes := make([]byte, 2)
r.Read(bunchBytes)
bunch := binary.BigEndian.Uint16(bunchBytes)
filecountBytes := make([]byte, 4)
r.Read(filecountBytes)
filecount := binary.BigEndian.Uint32(filecountBytes)
for i := uint32(0); i < filecount; i++ {
namelen := binary.BigEndian.Uint16(pkt.Data[si : 2+si])
name := pkt.Data[2+si : 2+si+uint32(namelen)]
datalen := binary.BigEndian.Uint32(pkt.Data[2+si+uint32(namelen) : 6+si+uint32(namelen)])
data := pkt.Data[6+si+uint32(namelen) : 6+uint32(si)+uint32(namelen)+datalen]
namelenBytes := make([]byte, 2)
r.Read(namelenBytes)
namelen := binary.BigEndian.Uint16(namelenBytes)
name := make([]byte, namelen)
r.Read(name)
datalenBytes := make([]byte, 4)
r.Read(datalenBytes)
datalen := binary.BigEndian.Uint32(datalenBytes)
data := make([]byte, datalen)
r.Read(data)
if media[string(name)] != nil && len(media[string(name)].data) == 0 {
media[string(name)].data = data
}
si += 6 + uint32(namelen) + datalen
}
if bunch >= bunchcount-1 {
p.SendDisco(0, true)
p.Close()
c.Close()
return
}
}
}
}
func (p *Peer) updateDetachedInvs(srvname string) {
func (c *Conn) updateDetachedInvs(srvname string) {
for i := range detachedinvs[srvname] {
data := make([]byte, 2+len(detachedinvs[srvname][i]))
data[0] = uint8(0x00)
data[1] = uint8(ToClientDetachedInventory)
copy(data[2:], detachedinvs[srvname][i])
ack, err := p.Send(rudp.Pkt{Data: data})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
@ -159,7 +201,7 @@ func (p *Peer) updateDetachedInvs(srvname string) {
}
}
func (p *Peer) announceMedia() {
func (c *Conn) announceMedia() {
srvname, ok := ConfKey("default_server").(string)
if !ok {
log.Print("Default server name not set or not a string")
@ -172,7 +214,7 @@ func (p *Peer) announceMedia() {
binary.BigEndian.PutUint32(data[2:6], uint32(len(nodedef)))
copy(data[6:], nodedef)
ack, err := p.Send(rudp.Pkt{Data: data})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
@ -184,35 +226,13 @@ func (p *Peer) announceMedia() {
binary.BigEndian.PutUint32(data[2:6], uint32(len(itemdef)))
copy(data[6:], itemdef)
ack, err = p.Send(rudp.Pkt{Data: data})
ack, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
<-ack
p.updateDetachedInvs(srvname)
data = make([]byte, 2+len(movement))
data[0] = uint8(0x00)
data[1] = uint8(ToClientMovement)
copy(data[2:], movement)
ack, err = p.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
}
<-ack
data = make([]byte, 2+len(timeofday))
data[0] = uint8(0x00)
data[1] = uint8(ToClientTimeOfDay)
copy(data[2:], timeofday)
ack, err = p.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
}
<-ack
c.updateDetachedInvs(srvname)
csmrf, ok := ConfKey("csm_restriction_flags").(int)
if !ok {
@ -226,7 +246,7 @@ func (p *Peer) announceMedia() {
binary.BigEndian.PutUint32(data[6:10], uint32(csmrf))
binary.BigEndian.PutUint32(data[10:], uint32(0))
ack, err = p.Send(rudp.Pkt{Data: data})
ack, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
@ -252,7 +272,7 @@ func (p *Peer) announceMedia() {
data[si] = uint8(0x00)
data[1+si] = uint8(0x00)
ack, err = p.Send(rudp.Pkt{Data: data})
ack, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
return
@ -260,7 +280,7 @@ func (p *Peer) announceMedia() {
<-ack
}
func (p *Peer) sendMedia(rqdata []byte) {
func (c *Conn) sendMedia(rqdata []byte) {
var rq []string
count := binary.BigEndian.Uint16(rqdata[0:2])
si := uint16(2)
@ -295,7 +315,13 @@ func (p *Peer) sendMedia(rqdata []byte) {
data[sj] = uint8(0x00)
data[1+sj] = uint8(0x00)
ack, err := p.Send(rudp.Pkt{Data: data, ChNo: 2})
ack, err := c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 2,
},
})
if err != nil {
log.Print(err)
return
@ -377,7 +403,7 @@ func loadMedia(servers map[string]struct{}) {
loadMediaCache()
clt := &Peer{username: "media"}
clt := &Conn{username: "media"}
for server := range servers {
straddr := ConfKey("servers:" + server + ":address")
@ -392,13 +418,13 @@ func loadMedia(servers map[string]struct{}) {
log.Fatal(err)
}
srv, err := Connect(conn, conn.RemoteAddr())
srv, err := Connect(conn)
if err != nil {
log.Print(err)
continue
}
fin := make(chan *Peer) // close-only
fin := make(chan *Conn) // close-only
go Init(clt, srv, false, true, fin)
<-fin

View File

@ -5,6 +5,7 @@ media and definition multiplexing
package main
import (
"bytes"
"log"
"net"
@ -48,7 +49,7 @@ func main() {
log.Print(clt.Addr(), " connected")
fin := make(chan *Peer)
fin := make(chan *Conn)
go Init(nil, clt, true, false, fin)
go func() {
@ -61,16 +62,15 @@ func main() {
}
select {
case <-clt.Disco():
case <-clt.Closed():
default:
ack, err := clt.Send(rudp.Pkt{Data: data})
ack, err := clt.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
<-ack
}
clt.SendDisco(0, true)
clt.Close()
return
}

15
packet.go Normal file
View File

@ -0,0 +1,15 @@
package main
import (
"bytes"
"github.com/anon55555/mt/rudp"
)
func ByteReader(pkt rudp.Pkt) *bytes.Reader {
buf := make([]byte, rudp.MaxUnrelPktSize)
n, _ := pkt.Read(buf)
buf = buf[:n]
return bytes.NewReader(buf)
}

166
peer.go
View File

@ -1,166 +0,0 @@
package main
import (
"fmt"
"net"
"sync"
"time"
"github.com/anon55555/mt"
"github.com/anon55555/mt/rudp"
)
var connectedPeers int = 0
var connectedPeersMu sync.RWMutex
// A Peer is a connection to a client or server
type Peer struct {
*rudp.Peer
protoVer uint16
username string
srp_s []byte
srp_A []byte
srp_a []byte
srp_B []byte
srp_K []byte
authMech int
sudoMode bool
stopforward bool
forwardMu sync.RWMutex
redirectMu sync.Mutex
srvMu sync.RWMutex
srv *Peer
initAoReceived bool
aoIDs map[uint16]bool
localPlayerCao uint16
currentPlayerCao uint16
useRpcMu sync.RWMutex
useRpc bool
noClt bool
modChs map[string]bool
huds map[uint32]bool
sounds map[int32]bool
blocks [][3]int16
inv *mt.Inv
}
// ProtoVer returns the protocol version of the Peer
func (p *Peer) ProtoVer() uint16 { return p.protoVer }
// Username returns the username of the Peer
// if it isn't a server
func (p *Peer) Username() string { return p.username }
// Forward reports whether the Proxy func should continue or stop
func (p *Peer) Forward() bool {
p.forwardMu.RLock()
defer p.forwardMu.RUnlock()
return !p.stopforward
}
// stopForwarding tells the Proxy func to stop
func (p *Peer) stopForwarding() {
p.forwardMu.Lock()
defer p.forwardMu.Unlock()
p.stopforward = true
}
// Server returns the Peer this Peer is connected to
// if it isn't a server
func (p *Peer) Server() *Peer {
p.srvMu.RLock()
defer p.srvMu.RUnlock()
return p.srv
}
// ServerName returns the name of the Peer this Peer is connected to
// if this Peer is not a server
func (p *Peer) ServerName() string {
servers := ConfKey("servers").(map[interface{}]interface{})
for server := range servers {
if ConfKey("servers:"+server.(string)+":address") == p.Server().Addr().String() {
return server.(string)
}
}
return ""
}
// SetServer sets the Peer this Peer is connected to
// if this Peer is not a server
func (p *Peer) SetServer(s *Peer) {
p.srvMu.Lock()
defer p.srvMu.Unlock()
p.srv = s
}
// UseRpc reports whether RPC messages can be sent to the Peer
func (p *Peer) UseRpc() bool {
p.useRpcMu.RLock()
defer p.useRpcMu.RUnlock()
return p.useRpc
}
// SetUseRpc sets the value returned by UseRpc
func (p *Peer) SetUseRpc(useRpc bool) {
p.useRpcMu.Lock()
defer p.useRpcMu.Unlock()
p.useRpc = useRpc
}
// NoClt reports whether the Peer is RPC-only
func (p *Peer) NoClt() bool { return p.noClt }
// MakeRpcOnly marks the Peer as RPC-only
func (p *Peer) MakeRpcOnly() {
p.noClt = true
}
// Inv returns the inventory of the Peer
func (p *Peer) Inv() *mt.Inv { return p.inv }
// Connect connects to the server on conn
// and closes conn when the Peer disconnects
func Connect(conn net.PacketConn, addr net.Addr) (*Peer, error) {
srv := &Peer{Peer: rudp.Connect(conn, addr)}
ack, err := srv.Send(rudp.Pkt{Data: []byte{0, 0}})
if err != nil {
return nil, err
}
select {
case <-time.After(8 * time.Second):
srv.SendDisco(0, true)
srv.Close()
return nil, fmt.Errorf("server at %s is unreachable", addr.String())
case <-ack:
}
return srv, nil
}
// PeerCount reports how many client Peers are connected
func PeerCount() int {
connectedPeersMu.RLock()
defer connectedPeersMu.RUnlock()
return connectedPeers
}

View File

@ -5,56 +5,56 @@ import "sync"
var onlinePlayers map[string]bool
var onlinePlayerMu sync.RWMutex
var onJoinPlayer []func(*Peer)
var onLeavePlayer []func(*Peer)
var onJoinPlayer []func(*Conn)
var onLeavePlayer []func(*Conn)
// RegisterOnJoinPlayer registers a callback function that is called
// when a TOSERVER_CLIENT_READY pkt is received from the Peer
func RegisterOnJoinPlayer(function func(*Peer)) {
// when a TOSERVER_CLIENT_READY pkt is received from the Conn
func RegisterOnJoinPlayer(function func(*Conn)) {
onJoinPlayer = append(onJoinPlayer, function)
}
// RegisterOnLeavePlayer registers a callback function that is called
// when a client Peer disconnects
func RegisterOnLeavePlayer(function func(*Peer)) {
// when a client Conn disconnects
func RegisterOnLeavePlayer(function func(*Conn)) {
onLeavePlayer = append(onLeavePlayer, function)
}
func processJoin(p *Peer) {
func processJoin(c *Conn) {
onlinePlayerMu.Lock()
defer onlinePlayerMu.Unlock()
cltSrv := p.ServerName()
for ; cltSrv == ""; cltSrv = p.ServerName() {
cltSrv := c.ServerName()
for ; cltSrv == ""; cltSrv = c.ServerName() {
}
rpcSrvMu.Lock()
for srv := range rpcSrvs {
srv.doRpc("->JOIN "+p.Username()+" "+cltSrv, "--")
srv.doRpc("->JOIN "+c.Username()+" "+cltSrv, "--")
}
rpcSrvMu.Unlock()
onlinePlayers[p.Username()] = true
onlinePlayers[c.Username()] = true
for i := range onJoinPlayer {
onJoinPlayer[i](p)
onJoinPlayer[i](c)
}
go OptimizeRPCConns()
}
func processLeave(p *Peer) {
func processLeave(c *Conn) {
onlinePlayerMu.Lock()
defer onlinePlayerMu.Unlock()
rpcSrvMu.Lock()
for srv := range rpcSrvs {
srv.doRpc("->LEAVE "+p.Username(), "--")
srv.doRpc("->LEAVE "+c.Username(), "--")
}
rpcSrvMu.Unlock()
onlinePlayers[p.Username()] = false
onlinePlayers[c.Username()] = false
for i := range onLeavePlayer {
onLeavePlayer[i](p)
onLeavePlayer[i](c)
}
}

View File

@ -131,12 +131,12 @@ func Privs(name string) (map[string]bool, error) {
return decodePrivs(eprivs), nil
}
// Privs returns the privileges of the Peer
func (p *Peer) Privs() (map[string]bool, error) {
return Privs(p.Username())
// Privs returns the privileges of a Conn
func (c *Conn) Privs() (map[string]bool, error) {
return Privs(c.Username())
}
// SetPrivs sets the privileges for a player
// SetPrivs sets the privileges of a player
func SetPrivs(name string, privs map[string]bool) error {
db, err := initAuthDB()
if err != nil {
@ -152,27 +152,30 @@ func SetPrivs(name string, privs map[string]bool) error {
return nil
}
// SetPrivs sets the privileges for the Peer
func (p *Peer) SetPrivs(privs map[string]bool) error {
return SetPrivs(p.Username(), privs)
// SetPrivs sets the privileges of a Conn
func (c *Conn) SetPrivs(privs map[string]bool) error {
return SetPrivs(c.Username(), privs)
}
// CheckPrivs reports if the Peer has all ofthe specified privileges
func (p *Peer) CheckPrivs(req map[string]bool) (bool, error) {
privs, err := p.Privs()
// CheckPrivs reports if a player has all of the specified privileges
func CheckPrivs(name string, req map[string]bool) (bool, error) {
privs, err := Privs(name)
if err != nil {
return false, err
}
allow := true
for priv := range req {
if req[priv] && !privs[priv] {
allow = false
break
return false, nil
}
}
return allow, nil
return true, nil
}
// CheckPrivs reports if a Conn has all of the specified privileges
func (c *Conn) CheckPrivs(req map[string]bool) (bool, error) {
return CheckPrivs(c.Username(), req)
}
func init() {

View File

@ -1,6 +1,7 @@
package main
import (
"bytes"
"errors"
"log"
"net"
@ -9,27 +10,23 @@ import (
)
// Proxy processes and forwards packets from src to dst
func Proxy(src, dst *Peer) {
func Proxy(src, dst *Conn) {
if src == nil {
data := []byte{
0, ToClientAccessDenied,
AccessDeniedServerFail, 0, 0, 0, 0,
}
_, err := dst.Send(rudp.Pkt{Data: data})
_, err := dst.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
dst.SendDisco(0, true)
dst.Close()
processLeave(dst)
return
} else if dst == nil {
src.SendDisco(0, true)
src.Close()
return
}
@ -42,16 +39,16 @@ func Proxy(src, dst *Peer) {
}
if err != nil {
if errors.Is(err, net.ErrClosed) {
msg := src.Addr().String() + " disconnected"
if src.TimedOut() {
msg += " (timed out)"
if err = src.WhyClosed(); err != nil {
log.Print(src.Addr().String(), " disconnected with error: ", err)
} else {
log.Print(src.Addr().String(), " disconnected")
}
log.Print(msg)
if !src.IsSrv() {
connectedPeersMu.Lock()
connectedPeers--
connectedPeersMu.Unlock()
connectedConnsMu.Lock()
connectedConns--
connectedConnsMu.Unlock()
processLeave(src)
}
@ -74,6 +71,5 @@ func Proxy(src, dst *Peer) {
}
}
dst.SendDisco(0, true)
dst.Close()
}

View File

@ -12,16 +12,16 @@ import (
"github.com/anon55555/mt/rudp"
)
var onRedirectDone []func(*Peer, string, bool)
var onRedirectDone []func(*Conn, string, bool)
// RegisterOnRedirectDone registers a callback function that is called
// when the Peer.Redirect method exits
func RegisterOnRedirectDone(function func(*Peer, string, bool)) {
// when the Conn.Redirect method exits
func RegisterOnRedirectDone(function func(*Conn, string, bool)) {
onRedirectDone = append(onRedirectDone, function)
}
func processRedirectDone(p *Peer, newsrv string) {
success := p.ServerName() == newsrv
func processRedirectDone(c *Conn, newsrv string) {
success := c.ServerName() == newsrv
successstr := "false"
if success {
@ -30,28 +30,28 @@ func processRedirectDone(p *Peer, newsrv string) {
rpcSrvMu.Lock()
for srv := range rpcSrvs {
srv.doRpc("->REDIRECTED "+p.Username()+" "+newsrv+" "+successstr, "--")
srv.doRpc("->REDIRECTED "+c.Username()+" "+newsrv+" "+successstr, "--")
}
rpcSrvMu.Unlock()
for i := range onRedirectDone {
onRedirectDone[i](p, newsrv, success)
onRedirectDone[i](c, newsrv, success)
}
}
// Redirect sends the Peer to the minetest server named newsrv
func (p *Peer) Redirect(newsrv string) error {
p.redirectMu.Lock()
defer p.redirectMu.Unlock()
// Redirect sends the Conn to the minetest server named newsrv
func (c *Conn) Redirect(newsrv string) error {
c.redirectMu.Lock()
defer c.redirectMu.Unlock()
defer processRedirectDone(p, newsrv)
defer processRedirectDone(c, newsrv)
straddr, ok := ConfKey("servers:" + newsrv + ":address").(string)
if !ok {
return fmt.Errorf("server %s does not exist", newsrv)
}
if p.ServerName() == newsrv {
if c.ServerName() == newsrv {
return fmt.Errorf("already connected to server %s", newsrv)
}
@ -65,19 +65,17 @@ func (p *Peer) Redirect(newsrv string) error {
return err
}
srv, err := Connect(conn, conn.RemoteAddr())
srv, err := Connect(conn)
if err != nil {
return err
}
fin := make(chan *Peer) // close-only
go Init(p, srv, true, false, fin)
fin := make(chan *Conn) // close-only
go Init(c, srv, true, false, fin)
initOk := <-fin
if initOk == nil {
srv.SendDisco(0, true)
srv.Close()
return fmt.Errorf("initialization with server %s failed", newsrv)
}
@ -87,29 +85,31 @@ func (p *Peer) Redirect(newsrv string) error {
0x00, 0x00,
}
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
// Remove active objects
data = make([]byte, 6+len(p.aoIDs)*2)
data = make([]byte, 6+len(c.aoIDs)*2)
data[0] = uint8(0x00)
data[1] = uint8(ToClientActiveObjectRemoveAdd)
binary.BigEndian.PutUint16(data[2:4], uint16(len(p.aoIDs)))
binary.BigEndian.PutUint16(data[2:4], uint16(len(c.aoIDs)))
si := 4
for ao := range p.aoIDs {
for ao := range c.aoIDs {
binary.BigEndian.PutUint16(data[si:2+si], ao)
si += 2
}
binary.BigEndian.PutUint16(data[si:2+si], uint16(0))
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
p.aoIDs = make(map[uint16]bool)
c.aoIDs = make(map[uint16]bool)
// Remove MapBlocks
for _, block := range p.blocks {
for _, block := range c.blocks {
x := block[0]
y := block[1]
z := block[2]
@ -143,69 +143,93 @@ func (p *Peer) Redirect(newsrv string) error {
copy(data[8:8+len(blockdata)], blockdata)
copy(data[8+len(blockdata):], compNodes)
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
}
p.blocks = [][3]int16{}
c.blocks = [][3]int16{}
// Remove HUDs
data = []byte{0, ToClientHudSetParam, 0, 1, 0, 4, 0, 0, 0, 8}
_, err = p.Send(rudp.Pkt{ChNo: 1, Data: data})
_, err = c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
return err
}
data = []byte{0, ToClientHudSetParam, 0, 2, 0, 0}
_, err = p.Send(rudp.Pkt{ChNo: 1, Data: data})
_, err = c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
return err
}
data = []byte{0, ToClientHudSetParam, 0, 3, 0, 0}
_, err = p.Send(rudp.Pkt{ChNo: 1, Data: data})
_, err = c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
return err
}
for hud := range p.huds {
for hud := range c.huds {
data = make([]byte, 6)
data[0] = uint8(0x00)
data[1] = uint8(ToClientHudRm)
binary.BigEndian.PutUint32(data[2:6], hud)
_, err = p.Send(rudp.Pkt{Data: data, ChNo: 1})
_, err = c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
return err
}
}
p.huds = make(map[uint32]bool)
c.huds = make(map[uint32]bool)
// Stop looped sounds
for sound := range p.sounds {
for sound := range c.sounds {
data = make([]byte, 6)
data[0] = uint8(0x00)
data[1] = uint8(ToClientStopSound)
binary.BigEndian.PutUint32(data[2:6], uint32(sound))
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
}
p.sounds = make(map[int32]bool)
c.sounds = make(map[int32]bool)
// Stop day/night ratio override
data = []byte{0, 0, 0}
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
@ -216,13 +240,13 @@ func (p *Peer) Redirect(newsrv string) error {
data = append(data, uint8(0))
}
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
// Reset sky
switch p.ProtoVer() {
switch c.ProtoVer() {
case 39:
data = []byte{
0, ToClientSetSky,
@ -249,7 +273,7 @@ func (p *Peer) Redirect(newsrv string) error {
}
}
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
@ -265,7 +289,7 @@ func (p *Peer) Redirect(newsrv string) error {
binary.BigEndian.PutUint32(sunscale[0:4], math.Float32bits(1))
data = append(data, sunscale...)
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
@ -280,7 +304,7 @@ func (p *Peer) Redirect(newsrv string) error {
binary.BigEndian.PutUint32(moonscale, math.Float32bits(1))
data = append(data, moonscale...)
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
@ -295,7 +319,7 @@ func (p *Peer) Redirect(newsrv string) error {
binary.BigEndian.PutUint32(starscale, math.Float32bits(1))
data = append(data, starscale...)
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
@ -309,7 +333,7 @@ func (p *Peer) Redirect(newsrv string) error {
binary.BigEndian.PutUint32(data, math.Float32bits(0))
binary.BigEndian.PutUint32(data, math.Float32bits(0))
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
@ -322,35 +346,35 @@ func (p *Peer) Redirect(newsrv string) error {
data[1] = uint8(ToClientDetachedInventory)
copy(data[2:], detachedinvs[newsrv][i])
_, err = p.Send(rudp.Pkt{Data: data})
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
}
}
p.Server().stopForwarding()
c.Server().stopForwarding()
p.SetServer(srv)
c.SetServer(srv)
go Proxy(p, srv)
go Proxy(srv, p)
go Proxy(c, srv)
go Proxy(srv, c)
// Rejoin mod channels
for ch := range p.modChs {
for ch := range c.modChs {
data := make([]byte, 4+len(ch))
data[0] = uint8(0x00)
data[1] = uint8(ToServerModChannelJoin)
binary.BigEndian.PutUint16(data[2:4], uint16(len(ch)))
copy(data[4:], []byte(ch))
_, err = srv.Send(rudp.Pkt{Data: data})
_, err = srv.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
}
log.Print(p.Addr().String() + " redirected to " + newsrv)
log.Print(c.Addr().String() + " redirected to " + newsrv)
return nil
}

167
rpc.go
View File

@ -1,8 +1,10 @@
package main
import (
"bytes"
"encoding/binary"
"errors"
"io"
"log"
"net"
"strconv"
@ -31,43 +33,60 @@ const (
)
var rpcSrvMu sync.Mutex
var rpcSrvs map[*Peer]struct{}
var rpcSrvs map[*Conn]struct{}
func (p *Peer) joinRpc() {
func (c *Conn) joinRpc() {
data := make([]byte, 4+len(rpcCh))
data[0] = uint8(0x00)
data[1] = uint8(ToServerModChannelJoin)
binary.BigEndian.PutUint16(data[2:4], uint16(len(rpcCh)))
copy(data[4:], []byte(rpcCh))
ack, err := p.Send(rudp.Pkt{Data: data})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return
}
<-ack
}
func (p *Peer) leaveRpc() {
func (c *Conn) leaveRpc() {
data := make([]byte, 4+len(rpcCh))
data[0] = uint8(0x00)
data[1] = uint8(ToServerModChannelLeave)
binary.BigEndian.PutUint16(data[2:4], uint16(len(rpcCh)))
copy(data[4:], []byte(rpcCh))
ack, err := p.Send(rudp.Pkt{Data: data})
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return
}
<-ack
}
func processRpc(p *Peer, pkt rudp.Pkt) bool {
chlen := binary.BigEndian.Uint16(pkt.Data[2:4])
ch := string(pkt.Data[4 : 4+chlen])
senderlen := binary.BigEndian.Uint16(pkt.Data[4+chlen : 6+chlen])
sender := string(pkt.Data[6+chlen : 6+chlen+senderlen])
msglen := binary.BigEndian.Uint16(pkt.Data[6+chlen+senderlen : 8+chlen+senderlen])
msg := string(pkt.Data[8+chlen+senderlen : 8+chlen+senderlen+msglen])
func processRpc(c *Conn, r *bytes.Reader) bool {
chlenBytes := make([]byte, 2)
r.Read(chlenBytes)
chlen := binary.BigEndian.Uint16(chlenBytes)
chBytes := make([]byte, chlen)
r.Read(chBytes)
ch := string(chBytes)
senderlenBytes := make([]byte, 2)
r.Read(senderlenBytes)
senderlen := binary.BigEndian.Uint16(senderlenBytes)
senderBytes := make([]byte, senderlen)
r.Read(senderBytes)
sender := string(senderBytes)
msglenBytes := make([]byte, 2)
r.Read(msglenBytes)
msglen := binary.BigEndian.Uint16(msglenBytes)
msgBytes := make([]byte, msglen)
r.Read(msgBytes)
msg := string(msgBytes)
if ch != rpcCh || sender != "" {
return false
@ -83,63 +102,63 @@ func processRpc(p *Peer, pkt rudp.Pkt) bool {
if !ok {
return true
}
go p.doRpc("->DEFSRV "+defsrv, rq)
go c.doRpc("->DEFSRV "+defsrv, rq)
case "<-GETPEERCNT":
cnt := strconv.Itoa(PeerCount())
go p.doRpc("->PEERCNT "+cnt, rq)
cnt := strconv.Itoa(ConnCount())
go c.doRpc("->PEERCNT "+cnt, rq)
case "<-ISONLINE":
online := "false"
if IsOnline(strings.Join(strings.Split(msg, " ")[2:], " ")) {
online = "true"
}
go p.doRpc("->ISONLINE "+online, rq)
go c.doRpc("->ISONLINE "+online, rq)
case "<-CHECKPRIVS":
name := strings.Split(msg, " ")[2]
privs := decodePrivs(strings.Join(strings.Split(msg, " ")[3:], " "))
hasprivs := "false"
if IsOnline(name) {
has, err := PeerByUsername(name).CheckPrivs(privs)
has, err := ConnByUsername(name).CheckPrivs(privs)
if err == nil && has {
hasprivs = "true"
}
}
go p.doRpc("->HASPRIVS "+hasprivs, rq)
go c.doRpc("->HASPRIVS "+hasprivs, rq)
case "<-GETPRIVS":
name := strings.Split(msg, " ")[2]
var r string
if IsOnline(name) {
privs, err := PeerByUsername(name).Privs()
privs, err := ConnByUsername(name).Privs()
if err == nil {
r = strings.Replace(encodePrivs(privs), "|", ",", -1)
}
}
go p.doRpc("->PRIVS "+r, rq)
go c.doRpc("->PRIVS "+r, rq)
case "<-SETPRIVS":
name := strings.Split(msg, " ")[2]
privs := decodePrivs(strings.Join(strings.Split(msg, " ")[3:], " "))
if IsOnline(name) {
PeerByUsername(name).SetPrivs(privs)
ConnByUsername(name).SetPrivs(privs)
}
case "<-GETSRV":
name := strings.Split(msg, " ")[2]
var srv string
if IsOnline(name) {
srv = PeerByUsername(name).ServerName()
srv = ConnByUsername(name).ServerName()
}
go p.doRpc("->SRV "+srv, rq)
go c.doRpc("->SRV "+srv, rq)
case "<-REDIRECT":
name := strings.Split(msg, " ")[2]
tosrv := strings.Split(msg, " ")[3]
if IsOnline(name) {
go PeerByUsername(name).Redirect(tosrv)
go ConnByUsername(name).Redirect(tosrv)
}
case "<-GETADDR":
name := strings.Split(msg, " ")[2]
var addr string
if IsOnline(name) {
addr = PeerByUsername(name).Addr().String()
addr = ConnByUsername(name).Addr().String()
}
go p.doRpc("->ADDR "+addr, rq)
go c.doRpc("->ADDR "+addr, rq)
case "<-ISBANNED":
db, err := initAuthDB()
if err != nil {
@ -163,17 +182,17 @@ func processRpc(p *Peer, pkt rudp.Pkt) bool {
r = "true"
}
go p.doRpc("->ISBANNED "+r, rq)
go c.doRpc("->ISBANNED "+r, rq)
case "<-BAN":
target := strings.Split(msg, " ")[2]
err := Ban(target)
if err != nil {
p2 := PeerByUsername(target)
if p2 == nil {
c2 := ConnByUsername(target)
if c2 == nil {
return true
}
p2.Ban()
c2.Ban()
}
case "<-UNBAN":
target := strings.Split(msg, " ")[2]
@ -187,12 +206,12 @@ func processRpc(p *Peer, pkt rudp.Pkt) bool {
}
srvs = srvs[:len(srvs)-1]
go p.doRpc("->SRVS "+srvs, rq)
go c.doRpc("->SRVS "+srvs, rq)
case "<-MT2MT":
msg := strings.Join(strings.Split(msg, " ")[2:], " ")
rpcSrvMu.Lock()
for srv := range rpcSrvs {
if srv.Addr().String() != p.Addr().String() {
if srv.Addr().String() != c.Addr().String() {
go srv.doRpc("->MT2MT true "+msg, "--")
}
}
@ -200,7 +219,7 @@ func processRpc(p *Peer, pkt rudp.Pkt) bool {
case "<-MSG2MT":
tosrv := strings.Split(msg, " ")[2]
addr, ok := ConfKey("servers:" + tosrv + ":address").(string)
if !ok || addr == p.Addr().String() {
if !ok || addr == c.Addr().String() {
return true
}
@ -216,8 +235,8 @@ func processRpc(p *Peer, pkt rudp.Pkt) bool {
return true
}
func (p *Peer) doRpc(rpc, rq string) {
if !p.UseRpc() {
func (c *Conn) doRpc(rpc, rq string) {
if !c.UseRpc() {
return
}
@ -231,7 +250,7 @@ func (p *Peer) doRpc(rpc, rq string) {
binary.BigEndian.PutUint16(data[4+len(rpcCh):6+len(rpcCh)], uint16(len(msg)))
copy(data[6+len(rpcCh):6+len(rpcCh)+len(msg)], []byte(msg))
_, err := p.Send(rudp.Pkt{Data: data})
_, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return
}
@ -242,7 +261,7 @@ func connectRpc() {
servers := ConfKey("servers").(map[interface{}]interface{})
for server := range servers {
clt := &Peer{username: "rpc"}
clt := &Conn{username: "rpc"}
straddr := ConfKey("servers:" + server.(string) + ":address")
@ -258,13 +277,13 @@ func connectRpc() {
continue
}
srv, err := Connect(conn, conn.RemoteAddr())
srv, err := Connect(conn)
if err != nil {
log.Print(err)
continue
}
fin := make(chan *Peer) // close-only
fin := make(chan *Conn) // close-only
go Init(clt, srv, true, true, fin)
go func() {
@ -280,7 +299,7 @@ func connectRpc() {
}
}
func handleRpc(srv *Peer) {
func handleRpc(srv *Conn) {
srv.MakeRpcOnly()
for {
pkt, err := srv.Recv()
@ -296,23 +315,38 @@ func handleRpc(srv *Peer) {
continue
}
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
r := ByteReader(pkt)
cmdBytes := make([]byte, 2)
r.Read(cmdBytes)
switch cmd := binary.BigEndian.Uint16(cmdBytes); cmd {
case ToClientModChannelSignal:
chlen := binary.BigEndian.Uint16(pkt.Data[3:5])
ch := string(pkt.Data[5 : 5+chlen])
r.Seek(1, io.SeekCurrent)
chlenBytes := make([]byte, 2)
r.Read(chlenBytes)
chlen := binary.BigEndian.Uint16(chlenBytes)
chBytes := make([]byte, chlen)
r.Read(chBytes)
ch := string(chBytes)
state, _ := r.ReadByte()
if ch == rpcCh {
switch sig := pkt.Data[2]; sig {
r.Seek(2, io.SeekStart)
switch sig, _ := r.ReadByte(); sig {
case ModChSigJoinOk:
srv.SetUseRpc(true)
case ModChSigSetState:
state := pkt.Data[5+chlen]
if state == ModChStateRO {
srv.SetUseRpc(false)
}
}
}
case ToClientModChannelMsg:
processRpc(srv, pkt)
processRpc(srv, r)
}
}
}
@ -322,35 +356,34 @@ func OptimizeRPCConns() {
defer rpcSrvMu.Unlock()
ServerLoop:
for p := range rpcSrvs {
for _, p2 := range Peers() {
if p2.Server() == nil {
for c := range rpcSrvs {
for _, c2 := range Conns() {
if c2.Server() == nil {
continue
}
if p2.Server().Addr().String() == p.Addr().String() {
if p.NoClt() {
p.SendDisco(0, true)
p.Close()
if c2.Server().Addr().String() == c.Addr().String() {
if c.NoClt() {
c.Close()
} else {
p.SetUseRpc(false)
p.leaveRpc()
c.SetUseRpc(false)
c.leaveRpc()
}
delete(rpcSrvs, p)
delete(rpcSrvs, c)
p3 := p2.Server()
p3.SetUseRpc(true)
p3.joinRpc()
c3 := c2.Server()
c3.SetUseRpc(true)
c3.joinRpc()
rpcSrvs[p3] = struct{}{}
rpcSrvs[c3] = struct{}{}
go func() {
<-p3.Disco()
<-c3.Closed()
rpcSrvMu.Lock()
delete(rpcSrvs, p3)
delete(rpcSrvs, c3)
rpcSrvMu.Unlock()
for p2.Server().Addr().String() == p3.Addr().String() {
for c2.Server().Addr().String() == c3.Addr().String() {
}
OptimizeRPCConns()
}()
@ -367,7 +400,7 @@ func reconnectRpc(media bool) {
servers := ConfKey("servers").(map[interface{}]interface{})
ServerLoop:
for server := range servers {
clt := &Peer{username: "rpc"}
clt := &Conn{username: "rpc"}
straddr := ConfKey("servers:" + server.(string) + ":address").(string)
@ -398,13 +431,13 @@ ServerLoop:
continue
}
srv, err := Connect(conn, conn.RemoteAddr())
srv, err := Connect(conn)
if err != nil {
log.Print(err)
continue
}
fin := make(chan *Peer) // close-only
fin := make(chan *Conn) // close-only
go Init(clt, srv, true, true, fin)
go func() {
@ -422,7 +455,7 @@ ServerLoop:
func init() {
rpcSrvMu.Lock()
rpcSrvs = make(map[*Peer]struct{})
rpcSrvs = make(map[*Conn]struct{})
rpcSrvMu.Unlock()
reconnect, ok := ConfKey("server_reintegration_interval").(int)

View File

@ -35,7 +35,7 @@ func Announce(action string) error {
return err
}
peers := Peers()
conns := Conns()
mods, ok := ConfKey("serverlist_mods").([]string)
if !ok {
@ -43,8 +43,8 @@ func Announce(action string) error {
}
clients_list := make([]string, 0)
for _, peer := range peers {
clients_list = append(clients_list, peer.Username())
for _, conn := range conns {
clients_list = append(clients_list, conn.Username())
}
maxPeers, ok := ConfKey("player_limit").(int)
@ -86,7 +86,7 @@ func Announce(action string) error {
data["pvp"] = confBool("serverlist_pvp")
data["uptime"] = Uptime()
data["game_time"] = 0
data["clients"] = PeerCount()
data["clients"] = ConnCount()
data["clients_max"] = maxPeers
data["clients_list"] = clients_list
data["gameid"] = conf("serverlist_game")