-
Notifications
You must be signed in to change notification settings - Fork 0
/
bridge.go
165 lines (158 loc) · 5.1 KB
/
bridge.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package blastoff
import (
"log"
"github.com/codecat/go-enet"
"github.com/google/uuid"
)
func (server *BlastoffServer) bridgePeerToRemote(peer enet.Peer, peerIncomingPacket <-chan bridgePacket, closeSignal <-chan bool) {
remoteHost, err := enet.NewHost(nil, 100, 0, 0, 0)
var remotePeer enet.Peer
if err != nil {
log.Fatalf("Couldn't create host: %s", err.Error())
return
}
remoteHost.CompressWithRangeCoder()
var closed = false
var peerValidated = false
var peerToken []byte
var redirectChan = make(chan uuid.UUID, 1)
go func() {
// Handle messages to and from the client
peerLoop:
for {
select {
case uuid := <-redirectChan:
// The server has indicated that the client should be redirected to another server
remotePeer.Disconnect(0)
remotePeer, err = remoteHost.Connect(server.remoteAddressMap[uuid], 0, 0)
if err != nil {
log.Printf("Couldn't connect to server: %s\n", err.Error())
break peerLoop
}
err = remotePeer.SendBytes(peerToken, RemoteAdminChannelId, enet.PacketFlagReliable)
if err != nil {
log.Printf("Couldn't send token to server: %s\n", err.Error())
break peerLoop
}
case peerPacket := <-peerIncomingPacket:
if peerValidated {
// If the peer is already validated, we simply send the packet to the remote
if err := remotePeer.SendPacket(peerPacket.packet, peerPacket.channelID); err != nil {
log.Printf("Couldn't send packet to server: %s\n", err.Error())
peerPacket.packet.Destroy()
}
break
}
// Initialize the connection with the remote host.
// First, the client sends a packet:
// The first part is the UUID of the remote host they wish to connect to
// The second part is the token that the remote host will use to verify the connection
var data = peerPacket.packet.GetData()
peerPacket.packet.Destroy()
// if len(data) <= 36 {
// log.Println("Invalid packet data length")
// break peerLoop
// }
// uuid, err := uuid.Parse(string(data[:36]))
// if err != nil {
// log.Printf("Couldn't parse UUID: %s\n", err.Error())
// break peerLoop
// }
// if _, ok := server.remoteAddressMap[uuid]; !ok {
// log.Printf("Remote host ID %s not found.", uuid.String())
// break peerLoop
// }
peerToken = data
// Now we connect to the remote
remotePeer, err = remoteHost.Connect(defaultRemote, 250, 0)
if err != nil {
log.Printf("Couldn't connect to server: %s\n", err.Error())
break peerLoop
}
case <-closeSignal:
break peerLoop
}
}
closed = true
}()
// Handle incoming messages from the remote
// These are messages which the remote sends to the client
// Unless coming from channel RemoteAdminChannelId, then it's a message for the Blastoff server
remoteLoop:
for {
if closed {
break
}
ev := remoteHost.Service(10)
if ev.GetType() == enet.EventNone {
continue
}
switch ev.GetType() {
case enet.EventConnect:
err = remotePeer.SendBytes(peerToken, RemoteAdminChannelId, enet.PacketFlagReliable)
if err != nil {
log.Printf("Couldn't send token to server: %s\n", err.Error())
break remoteLoop
}
case enet.EventDisconnect:
break remoteLoop
case enet.EventReceive:
packet := ev.GetPacket()
if ev.GetChannelID() == RemoteAdminChannelId {
var data = packet.GetData()
packet.Destroy()
// This is a special communication packet from the server
// The first byte indicates the type of packet
switch ServerCommandFlag(data[0]) {
case ServerCommandNewInstance:
// The server is redirecting the client to another server
// The data contains the UUID of the server to redirect to
if len(data) < 37 {
log.Println("Invalid new instance data")
break remoteLoop
}
uuid, err := uuid.FromBytes(data[1:37])
if err != nil {
log.Printf("Couldn't parse UUID: %s\n", err.Error())
break remoteLoop
}
log.Printf("Spawning new instance: %s\n", uuid.String())
case ServerCommandValidateClient:
peerValidated = true
case ServerCommandRedirectClient:
// The client is being redirected to another server
// The data contains the UUID of the server to redirect to
if len(data) < 37 {
log.Println("Invalid redirect data length")
break remoteLoop
}
uuid, err := uuid.FromBytes(data[1:37])
if err != nil {
log.Printf("Couldn't parse UUID: %s\n", err.Error())
break remoteLoop
}
if _, ok := server.remoteAddressMap[uuid]; !ok {
log.Printf("Remote host ID %s not found during redirect.", uuid.String())
break remoteLoop
}
default:
log.Println("Client validation failed")
break remoteLoop
}
continue
} else {
if !peerValidated {
// This is a bug. The server should not be sending messages through this stream before the client is validated.
log.Println("Client not validated.")
break remoteLoop
}
if err := peer.SendPacket(packet, ev.GetChannelID()); err != nil {
log.Printf("Couldn't send packet to client: %s\n", err.Error())
packet.Destroy()
}
}
}
}
peer.Disconnect(0)
remoteHost.Destroy()
}