Use new RUDP version
parent
bb337e00c3
commit
1540fd54f5
|
@ -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
24
ban.go
|
@ -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
|
||||
}
|
||||
|
|
66
blockdata.go
66
blockdata.go
|
@ -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
60
chat.go
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
248
command.go
248
command.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
9
end.go
|
@ -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
2
go.mod
|
@ -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
4
go.sum
|
@ -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
16
hand.go
|
@ -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,
|
||||
}
|
||||
|
|
174
igutils.go
174
igutils.go
|
@ -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
376
init.go
|
@ -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
|
||||
|
|
73
listen.go
73
listen.go
|
@ -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
170
media.go
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
166
peer.go
|
@ -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
|
||||
}
|
32
player.go
32
player.go
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
31
privs.go
31
privs.go
|
@ -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() {
|
||||
|
|
24
proxy.go
24
proxy.go
|
@ -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()
|
||||
}
|
||||
|
|
128
redirect.go
128
redirect.go
|
@ -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
167
rpc.go
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in New Issue