forked from HimbeerserverDE/multiserver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
redirect.go
138 lines (108 loc) · 2.85 KB
/
redirect.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main
import (
"encoding/binary"
"errors"
"log"
"net"
"github.com/anon55555/mt/rudp"
)
var ErrServerDoesNotExist = errors.New("server doesn't exist")
var ErrAlreadyConnected = errors.New("already connected to server")
var onRedirectDone []func(*Peer, string, bool)
// RegisterOnRedirectDone registers a callback function that is called
// when the Peer.Redirect method exits
func RegisterOnRedirectDone(function func(*Peer, string, bool)) {
onRedirectDone = append(onRedirectDone, function)
}
func processRedirectDone(p *Peer, newsrv string) {
success := p.ServerName() == newsrv
successstr := "false"
if success {
successstr = "true"
}
rpcSrvMu.Lock()
for srv := range rpcSrvs {
srv.doRpc("->REDIRECTED "+string(p.username)+" "+newsrv+" "+successstr, "--")
}
rpcSrvMu.Unlock()
for i := range onRedirectDone {
onRedirectDone[i](p, 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()
defer processRedirectDone(p, newsrv)
straddr, ok := GetConfKey("servers:" + newsrv + ":address").(string)
if !ok {
return ErrServerDoesNotExist
}
if p.Server().Addr().String() == straddr {
return ErrAlreadyConnected
}
srvaddr, err := net.ResolveUDPAddr("udp", straddr)
if err != nil {
return err
}
conn, err := net.DialUDP("udp", nil, srvaddr)
if err != nil {
return err
}
srv, err := Connect(conn, conn.RemoteAddr())
if err != nil {
return err
}
// Remove active objects
data := make([]byte, 6+len(p.aoIDs)*2)
data[0] = uint8(0x00)
data[1] = uint8(ToClientActiveObjectRemoveAdd)
binary.BigEndian.PutUint16(data[2:4], uint16(len(p.aoIDs)))
i := 4
for ao := range p.aoIDs {
binary.BigEndian.PutUint16(data[i:2+i], ao)
i += 2
}
binary.BigEndian.PutUint16(data[i:2+i], uint16(0))
if len(detachedinvs[newsrv]) > 0 {
for i := range detachedinvs[newsrv] {
data := make([]byte, 2+len(detachedinvs[newsrv][i]))
data[0] = uint8(0x00)
data[1] = uint8(ToClientDetachedInventory)
copy(data[2:], detachedinvs[newsrv][i])
ack, err := p.Send(rudp.Pkt{Data: data})
if err != nil {
return err
}
<-ack
}
}
ack, err := p.Send(rudp.Pkt{Data: data})
if err != nil {
return err
}
<-ack
p.aoIDs = make(map[uint16]bool)
p.Server().stopForwarding()
fin := make(chan *Peer) // close-only
go Init(p, srv, true, false, fin)
<-fin
p.SetServer(srv)
go Proxy(p, srv)
go Proxy(srv, p)
// Rejoin mod channels
for ch := range p.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))
ack, err := srv.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
}
<-ack
}
log.Print(p.Addr().String() + " redirected to " + newsrv)
return nil
}