clean up connection code
This commit is contained in:
parent
02b92b9788
commit
4068840bdf
59
capture.go
59
capture.go
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/google/gopacket/pcapgo"
|
||||
"github.com/sandertv/gophertunnel/minecraft"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
@ -83,46 +82,12 @@ func packets_main(ctx context.Context, args []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
var hostname string
|
||||
hostname, server = server_input(server)
|
||||
address, hostname, err := server_input(server)
|
||||
|
||||
_status := minecraft.NewStatusProvider("Server")
|
||||
listener, err := minecraft.ListenConfig{
|
||||
StatusProvider: _status,
|
||||
}.Listen("raknet", ":19132")
|
||||
listener, serverConn, clientConn, err := create_proxy(ctx, address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
fmt.Printf("Listening on %s\n", listener.Addr())
|
||||
|
||||
c, err := listener.Accept()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
conn := c.(*minecraft.Conn)
|
||||
|
||||
var packet_func func(header packet.Header, payload []byte, src, dst net.Addr) = nil
|
||||
if G_debug {
|
||||
packet_func = PacketLogger
|
||||
}
|
||||
|
||||
fmt.Printf("Connecting to %s\n", server)
|
||||
serverConn, err := minecraft.Dialer{
|
||||
TokenSource: G_src,
|
||||
ClientData: conn.ClientData(),
|
||||
PacketFunc: packet_func,
|
||||
}.DialContext(ctx, "raknet", server)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to connect to %s: %s\n", server, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := spawn_conn(ctx, conn, serverConn); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to spawn: %s\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := os.Create(hostname + "-" + time.Now().Format("2006-01-02_15-04-05") + ".pcap")
|
||||
if err != nil {
|
||||
|
@ -133,25 +98,13 @@ func packets_main(ctx context.Context, args []string) error {
|
|||
w.WriteFileHeader(65536, layers.LinkTypeEthernet)
|
||||
|
||||
_wl := sync.Mutex{}
|
||||
/* TEST
|
||||
{
|
||||
for i := 0; i < 1000; i++ {
|
||||
dump_packet(false, w, &packet.SetTitle{
|
||||
Text: fmt.Sprintf("Test %d", i),
|
||||
})
|
||||
dump_packet(true, w, &packet.MovePlayer{
|
||||
Tick: uint64(i),
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
*/
|
||||
|
||||
go func() {
|
||||
defer listener.Disconnect(conn, "connection lost")
|
||||
defer listener.Disconnect(clientConn, "connection lost")
|
||||
defer serverConn.Close()
|
||||
|
||||
for {
|
||||
pk, err := conn.ReadPacket()
|
||||
pk, err := clientConn.ReadPacket()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to read packet: %s\n", err)
|
||||
return
|
||||
|
@ -180,7 +133,7 @@ func packets_main(ctx context.Context, args []string) error {
|
|||
dump_packet(false, w, pk)
|
||||
_wl.Unlock()
|
||||
|
||||
err = conn.WritePacket(pk)
|
||||
err = clientConn.WritePacket(pk)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write packet: %s\n", err)
|
||||
return nil
|
||||
|
|
Binary file not shown.
|
@ -28,33 +28,19 @@ func skin_proxy_main(ctx context.Context, args []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
_status := minecraft.NewStatusProvider("Server")
|
||||
listener, err := minecraft.ListenConfig{
|
||||
StatusProvider: _status,
|
||||
}.Listen("raknet", ":19132")
|
||||
address, hostname, err := server_input(server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
listener, clientConn, serverConn, err := create_proxy(ctx, address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
fmt.Printf("Listening on %s\n", listener.Addr())
|
||||
|
||||
c, err := listener.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn := c.(*minecraft.Conn)
|
||||
|
||||
hostname, serverConn, err := connect_server(ctx, server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out_path := fmt.Sprintf("skins/%s", hostname)
|
||||
|
||||
if err := spawn_conn(ctx, conn, serverConn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
println("Connected")
|
||||
println("Press ctrl+c to exit")
|
||||
|
||||
|
@ -63,18 +49,18 @@ func skin_proxy_main(ctx context.Context, args []string) error {
|
|||
errs := make(chan error, 2)
|
||||
go func() { // server -> client
|
||||
defer serverConn.Close()
|
||||
defer listener.Disconnect(conn, "connection lost")
|
||||
defer listener.Disconnect(clientConn, "connection lost")
|
||||
for {
|
||||
pk, err := serverConn.ReadPacket()
|
||||
if err != nil {
|
||||
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
|
||||
_ = listener.Disconnect(conn, disconnect.Error())
|
||||
_ = listener.Disconnect(clientConn, disconnect.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
process_packet_skins(conn, out_path, pk)
|
||||
process_packet_skins(clientConn, out_path, pk)
|
||||
|
||||
if err = conn.WritePacket(pk); err != nil {
|
||||
if err = clientConn.WritePacket(pk); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -82,14 +68,14 @@ func skin_proxy_main(ctx context.Context, args []string) error {
|
|||
|
||||
go func() { // client -> server
|
||||
for {
|
||||
pk, err := conn.ReadPacket()
|
||||
pk, err := clientConn.ReadPacket()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := serverConn.WritePacket(pk); err != nil {
|
||||
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
|
||||
_ = listener.Disconnect(conn, disconnect.Error())
|
||||
_ = listener.Disconnect(clientConn, disconnect.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
7
skins.go
7
skins.go
|
@ -184,7 +184,12 @@ func skin_main(ctx context.Context, args []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
hostname, serverConn, err := connect_server(ctx, server)
|
||||
address, hostname, err := server_input(server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverConn, err := connect_server(ctx, address, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
104
utils.go
104
utils.go
|
@ -5,6 +5,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
|
||||
"github.com/sandertv/gophertunnel/minecraft"
|
||||
"github.com/sandertv/gophertunnel/minecraft/auth"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/login"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
@ -49,55 +51,69 @@ func get_token() oauth2.Token {
|
|||
return token
|
||||
}
|
||||
|
||||
func server_input(server string) (string, string) {
|
||||
if server == "" {
|
||||
func server_input(server string) (address, name string, err error) {
|
||||
if server == "" { // no arg provided, interactive input
|
||||
fmt.Printf("Enter Server: ")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
server, _ = reader.ReadString('\n')
|
||||
r, _ := regexp.Compile(`[\n\r]`)
|
||||
server = string(r.ReplaceAll([]byte(server), []byte("")))
|
||||
}
|
||||
if len(strings.Split(server, ":")) == 1 {
|
||||
server += ":19132"
|
||||
|
||||
if strings.HasPrefix(server, "realm:") { // for realms use api to get ip address
|
||||
name, address, err = get_realm(strings.Split(server, ":")[1])
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
} else {
|
||||
// if an actual server address if given
|
||||
// add port if necessary
|
||||
address = server
|
||||
if len(strings.Split(address, ":")) == 1 {
|
||||
address += ":19132"
|
||||
}
|
||||
name = server_url_to_name(address)
|
||||
}
|
||||
|
||||
return address, name, nil
|
||||
}
|
||||
|
||||
func server_url_to_name(server string) string {
|
||||
host, _, err := net.SplitHostPort(server)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Invalid server: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return host, server
|
||||
return host
|
||||
}
|
||||
|
||||
func connect_server(ctx context.Context, server string) (hostname string, conn *minecraft.Conn, err error) {
|
||||
if strings.HasPrefix(server, "realm:") {
|
||||
hostname, server, err = get_realm(strings.Split(server, ":")[1])
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
} else {
|
||||
hostname, server = server_input(server)
|
||||
}
|
||||
|
||||
func connect_server(ctx context.Context, address string, ClientData *login.ClientData) (serverConn *minecraft.Conn, err error) {
|
||||
var packet_func func(header packet.Header, payload []byte, src, dst net.Addr) = nil
|
||||
if G_debug {
|
||||
packet_func = PacketLogger
|
||||
}
|
||||
|
||||
fmt.Printf("Connecting to %s\n", server)
|
||||
conn, err = minecraft.Dialer{
|
||||
TokenSource: G_src,
|
||||
PacketFunc: packet_func,
|
||||
}.DialContext(ctx, "raknet", server)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
cd := login.ClientData{}
|
||||
if ClientData != nil {
|
||||
cd = *ClientData
|
||||
}
|
||||
return hostname, conn, nil
|
||||
|
||||
fmt.Printf("Connecting to %s\n", address)
|
||||
serverConn, err = minecraft.Dialer{
|
||||
TokenSource: G_src,
|
||||
ClientData: cd,
|
||||
PacketFunc: packet_func,
|
||||
}.DialContext(ctx, "raknet", address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return serverConn, nil
|
||||
}
|
||||
|
||||
func spawn_conn(ctx context.Context, conn *minecraft.Conn, serverConn *minecraft.Conn) error {
|
||||
func spawn_conn(ctx context.Context, clientConn *minecraft.Conn, serverConn *minecraft.Conn) error {
|
||||
errs := make(chan error, 2)
|
||||
go func() {
|
||||
errs <- conn.StartGame(serverConn.GameData())
|
||||
errs <- clientConn.StartGame(serverConn.GameData())
|
||||
}()
|
||||
go func() {
|
||||
errs <- serverConn.DoSpawn()
|
||||
|
@ -116,3 +132,41 @@ func spawn_conn(ctx context.Context, conn *minecraft.Conn, serverConn *minecraft
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func create_proxy(ctx context.Context, server_address string) (l *minecraft.Listener, clientConn, serverConn *minecraft.Conn, err error) {
|
||||
_status := minecraft.NewStatusProvider("Server")
|
||||
listener, err := minecraft.ListenConfig{
|
||||
StatusProvider: _status,
|
||||
}.Listen("raknet", ":19132")
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
l = listener
|
||||
|
||||
fmt.Printf("Listening on %s\n", listener.Addr())
|
||||
|
||||
c, err := listener.Accept()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
clientConn = c.(*minecraft.Conn)
|
||||
|
||||
cd := clientConn.ClientData()
|
||||
serverConn, err = connect_server(ctx, server_address, &cd)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to connect to %s: %s", server_address, err)
|
||||
}
|
||||
|
||||
if err := spawn_conn(ctx, clientConn, serverConn); err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to spawn: %s", err)
|
||||
}
|
||||
|
||||
G_exit = append(G_exit, func() {
|
||||
serverConn.Close()
|
||||
listener.Disconnect(clientConn, "Closing")
|
||||
clientConn.Close()
|
||||
listener.Close()
|
||||
})
|
||||
|
||||
return l, clientConn, serverConn, nil
|
||||
}
|
||||
|
|
105
world.go
105
world.go
|
@ -8,8 +8,6 @@ import (
|
|||
"image"
|
||||
"image/draw"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
|
@ -36,9 +34,11 @@ type TPlayerPos struct {
|
|||
// the state used for drawing and saving
|
||||
|
||||
type WorldState struct {
|
||||
chunks map[protocol.ChunkPos]*chunk.Chunk
|
||||
Dim world.Dimension
|
||||
WorldName string
|
||||
chunks map[protocol.ChunkPos]*chunk.Chunk
|
||||
Dim world.Dimension
|
||||
WorldName string
|
||||
ServerName string
|
||||
worldCounter int
|
||||
|
||||
PlayerPos TPlayerPos
|
||||
ClientConn *minecraft.Conn
|
||||
|
@ -66,13 +66,12 @@ func init() {
|
|||
}
|
||||
|
||||
func world_main(ctx context.Context, args []string) error {
|
||||
var server string
|
||||
var server_address string
|
||||
|
||||
if len(args) >= 1 {
|
||||
server = args[0]
|
||||
server_address = args[0]
|
||||
args = args[1:]
|
||||
}
|
||||
_, server = server_input(server)
|
||||
|
||||
flag.CommandLine.Parse(args)
|
||||
if G_help {
|
||||
|
@ -80,26 +79,16 @@ func world_main(ctx context.Context, args []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
_status := minecraft.NewStatusProvider("Server")
|
||||
listener, err := minecraft.ListenConfig{
|
||||
StatusProvider: _status,
|
||||
}.Listen("raknet", ":19132")
|
||||
server_address, hostname, err := server_input(server_address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
fmt.Printf("Listening on %s\n", listener.Addr())
|
||||
|
||||
c, err := listener.Accept()
|
||||
listener, clientConn, serverConn, err := create_proxy(ctx, server_address)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// not a goroutine, only 1 client at a time
|
||||
|
||||
world_state := NewWorldState()
|
||||
world_state.handleConn(ctx, c.(*minecraft.Conn), listener, server)
|
||||
handleConn(ctx, listener, clientConn, serverConn, hostname)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -188,9 +177,8 @@ func (w *WorldState) ProcessAnimate(pk *packet.Animate) {
|
|||
|
||||
func (w *WorldState) ProcessChangeDimension(pk *packet.ChangeDimension) {
|
||||
fmt.Printf("ChangeDimension %d\n", pk.Dimension)
|
||||
w.SaveAndReset()
|
||||
w.Dim = dimension_ids[pk.Dimension]
|
||||
w.chunks = make(map[protocol.ChunkPos]*chunk.Chunk)
|
||||
w.ui.Reset()
|
||||
}
|
||||
|
||||
func (w *WorldState) SetPlayerPos(Position mgl32.Vec3, Pitch, Yaw, HeadYaw float32) {
|
||||
|
@ -220,57 +208,36 @@ func (w *WorldState) SaveAndReset() {
|
|||
int(w.PlayerPos.Position[1]),
|
||||
int(w.PlayerPos.Position[2]),
|
||||
}
|
||||
|
||||
for _, gr := range w.ServerConn.GameData().GameRules {
|
||||
switch gr.Name {
|
||||
// todo
|
||||
}
|
||||
}
|
||||
|
||||
provider.SaveSettings(s)
|
||||
provider.Close()
|
||||
w.chunks = make(map[protocol.ChunkPos]*chunk.Chunk)
|
||||
w.ui.Reset()
|
||||
}
|
||||
|
||||
func (w *WorldState) handleConn(ctx context.Context, conn *minecraft.Conn, listener *minecraft.Listener, target string) {
|
||||
w.ClientConn = conn
|
||||
|
||||
var packet_func func(header packet.Header, payload []byte, src, dst net.Addr) = nil
|
||||
if G_debug {
|
||||
packet_func = PacketLogger
|
||||
}
|
||||
|
||||
fmt.Printf("Connecting to %s\n", target)
|
||||
serverConn, err := minecraft.Dialer{
|
||||
TokenSource: G_src,
|
||||
ClientData: conn.ClientData(),
|
||||
PacketFunc: packet_func,
|
||||
}.DialContext(ctx, "raknet", target)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to connect to %s: %s\n", target, err)
|
||||
return
|
||||
}
|
||||
w.ServerConn = serverConn
|
||||
|
||||
if err := spawn_conn(ctx, conn, serverConn); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to spawn: %s\n", err)
|
||||
return
|
||||
}
|
||||
func handleConn(ctx context.Context, l *minecraft.Listener, cc, sc *minecraft.Conn, server_name string) {
|
||||
w := NewWorldState()
|
||||
w.ServerName = server_name
|
||||
w.ClientConn = cc
|
||||
w.ServerConn = sc
|
||||
|
||||
G_exit = append(G_exit, func() {
|
||||
serverConn.Close()
|
||||
conn.WritePacket(&packet.Disconnect{
|
||||
Message: "Closing",
|
||||
HideDisconnectionScreen: false,
|
||||
})
|
||||
conn.Close()
|
||||
listener.Close()
|
||||
w.SaveAndReset()
|
||||
})
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() { // client loop
|
||||
defer listener.Disconnect(conn, "connection lost")
|
||||
defer serverConn.Close()
|
||||
defer func() { done <- struct{}{} }()
|
||||
for {
|
||||
skip := false
|
||||
pk, err := conn.ReadPacket()
|
||||
pk, err := w.ClientConn.ReadPacket()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -287,16 +254,16 @@ func (w *WorldState) handleConn(ctx context.Context, conn *minecraft.Conn, liste
|
|||
}
|
||||
case *packet.ClientCacheStatus:
|
||||
pk.Enabled = false
|
||||
serverConn.WritePacket(pk)
|
||||
w.ServerConn.WritePacket(pk)
|
||||
skip = true
|
||||
case *packet.Animate:
|
||||
w.ProcessAnimate(pk)
|
||||
}
|
||||
|
||||
if !skip {
|
||||
if err := serverConn.WritePacket(pk); err != nil {
|
||||
if err := w.ServerConn.WritePacket(pk); err != nil {
|
||||
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
|
||||
_ = listener.Disconnect(conn, disconnect.Error())
|
||||
_ = l.Disconnect(w.ClientConn, disconnect.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -311,7 +278,7 @@ func (w *WorldState) handleConn(ctx context.Context, conn *minecraft.Conn, liste
|
|||
default:
|
||||
for {
|
||||
time.Sleep(1 * time.Second)
|
||||
err := conn.WritePacket(&MAP_ITEM_PACKET)
|
||||
err := w.ClientConn.WritePacket(&MAP_ITEM_PACKET)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -320,11 +287,11 @@ func (w *WorldState) handleConn(ctx context.Context, conn *minecraft.Conn, liste
|
|||
}()
|
||||
|
||||
go func() { // server loop
|
||||
defer serverConn.Close()
|
||||
defer listener.Disconnect(conn, "connection lost")
|
||||
defer w.ServerConn.Close()
|
||||
defer l.Disconnect(w.ClientConn, "connection lost")
|
||||
defer func() { done <- struct{}{} }()
|
||||
|
||||
gd := serverConn.GameData()
|
||||
gd := w.ServerConn.GameData()
|
||||
w.ProcessChangeDimension(&packet.ChangeDimension{
|
||||
Dimension: gd.Dimension,
|
||||
Position: gd.PlayerPosition,
|
||||
|
@ -332,10 +299,10 @@ func (w *WorldState) handleConn(ctx context.Context, conn *minecraft.Conn, liste
|
|||
})
|
||||
|
||||
for {
|
||||
pk, err := serverConn.ReadPacket()
|
||||
pk, err := w.ServerConn.ReadPacket()
|
||||
if err != nil {
|
||||
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
|
||||
_ = listener.Disconnect(conn, disconnect.Error())
|
||||
_ = l.Disconnect(w.ClientConn, disconnect.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -346,12 +313,12 @@ func (w *WorldState) handleConn(ctx context.Context, conn *minecraft.Conn, liste
|
|||
case *packet.LevelChunk:
|
||||
w.ProcessLevelChunk(pk)
|
||||
w.ui.Send(w)
|
||||
send_popup(conn, fmt.Sprintf("%d chunks loaded\n", len(w.chunks)))
|
||||
send_popup(w.ClientConn, fmt.Sprintf("%d chunks loaded\n", len(w.chunks)))
|
||||
case *packet.SubChunk:
|
||||
w.ProcessSubChunk(pk)
|
||||
}
|
||||
|
||||
if err := conn.WritePacket(pk); err != nil {
|
||||
if err := w.ClientConn.WritePacket(pk); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue