Finished status and ping handling
This commit is contained in:
parent
dc9e176cc1
commit
f22a917f21
307
main.go
307
main.go
@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -11,11 +13,8 @@ const (
|
||||
HandshakePacketID = 0x00
|
||||
StatusRequestID = 0x00
|
||||
StatusResponseID = 0x00
|
||||
)
|
||||
|
||||
const (
|
||||
SEGMENT_BITS = 0x7F
|
||||
CONTINUE_BIT = 0x80
|
||||
PingRequestID = 0x01
|
||||
PongResponseID = 0x01
|
||||
)
|
||||
|
||||
type HandshakePacket struct {
|
||||
@ -42,6 +41,10 @@ type PlayerInfo struct {
|
||||
Sample []Player `json:"sample"`
|
||||
}
|
||||
|
||||
type Pong struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
Name string `json:"name"`
|
||||
ID string `json:"id"`
|
||||
@ -51,11 +54,6 @@ type Chat struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type Reader struct {
|
||||
data []byte
|
||||
cursor int
|
||||
}
|
||||
|
||||
type ClientState struct {
|
||||
conn net.Conn
|
||||
nextState int
|
||||
@ -79,7 +77,6 @@ func main() {
|
||||
}
|
||||
|
||||
client := &ClientState{conn: conn, nextState: 0}
|
||||
|
||||
go handleConnection(client)
|
||||
}
|
||||
}
|
||||
@ -88,10 +85,7 @@ func handleConnection(client *ClientState) {
|
||||
defer client.conn.Close()
|
||||
fmt.Println("New connection from:", client.conn.RemoteAddr())
|
||||
|
||||
r := &Reader{data: make([]byte, 0)}
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
for {
|
||||
n, err := client.conn.Read(buf)
|
||||
if err != nil {
|
||||
@ -99,25 +93,15 @@ func handleConnection(client *ClientState) {
|
||||
break
|
||||
}
|
||||
|
||||
// Append new data to the reader buffer
|
||||
r.data = append(r.data, buf[:n]...)
|
||||
reader := bytes.NewReader(buf[:n])
|
||||
|
||||
// Process packets as long as there is data
|
||||
for len(r.data) > 0 {
|
||||
startCursor := r.cursor
|
||||
|
||||
packetLength, err := r.readVarInt()
|
||||
if err != nil {
|
||||
r.cursor = startCursor // Reset if incomplete packet
|
||||
packetLength, err := readVarInt(reader)
|
||||
if err != nil || packetLength > reader.Len() {
|
||||
fmt.Println("Incomplete packet received")
|
||||
break
|
||||
}
|
||||
|
||||
if len(r.data[r.cursor:]) < packetLength {
|
||||
r.cursor = startCursor // Reset if incomplete packet
|
||||
break
|
||||
}
|
||||
|
||||
packetID, err := r.readVarInt()
|
||||
packetID, err := readVarInt(reader)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading packet ID:", err)
|
||||
break
|
||||
@ -125,50 +109,71 @@ func handleConnection(client *ClientState) {
|
||||
|
||||
fmt.Println("Packet ID:", packetID)
|
||||
|
||||
if packetID == StatusRequestID && client.nextState == 1 {
|
||||
handleStatusRequest(client.conn)
|
||||
switch packetID {
|
||||
case HandshakePacketID | StatusRequestID:
|
||||
if client.nextState == 1 {
|
||||
handleStatusRequest(client)
|
||||
} else {
|
||||
if packetID == HandshakePacketID {
|
||||
handshake, err := handleHandshake(r)
|
||||
handshake, err := handleHandshake(reader)
|
||||
if err != nil {
|
||||
fmt.Println("Error processing handshake:", err)
|
||||
return
|
||||
}
|
||||
client.nextState = handshake.NextState
|
||||
}
|
||||
case PingRequestID:
|
||||
var timestamp int64
|
||||
if err := binary.Read(reader, binary.BigEndian, ×tamp); err != nil {
|
||||
fmt.Println("Error reading timestamp:", err)
|
||||
break
|
||||
}
|
||||
|
||||
// Remove processed data
|
||||
r.data = r.data[r.cursor:]
|
||||
r.cursor = 0
|
||||
var responsePacket bytes.Buffer
|
||||
writeVarInt(&responsePacket, 9) // Packet length: 1 byte for ID + 8 bytes for timestamp
|
||||
responsePacket.WriteByte(PongResponseID)
|
||||
binary.Write(&responsePacket, binary.BigEndian, timestamp)
|
||||
|
||||
if _, err := client.conn.Write(responsePacket.Bytes()); err != nil {
|
||||
fmt.Println("Error sending pong response:", err)
|
||||
} else {
|
||||
fmt.Println("Pong response sent successfully:", timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleHandshake(r *Reader) (HandshakePacket, error) {
|
||||
func handleHandshake(reader *bytes.Reader) (HandshakePacket, error) {
|
||||
var handshake HandshakePacket
|
||||
if err := readHandshakePacket(r, &handshake); err != nil {
|
||||
fmt.Println("Error reading handshake packet:", err)
|
||||
var err error
|
||||
|
||||
handshake.ProtocolVersion, err = readVarInt(reader)
|
||||
if err != nil {
|
||||
return handshake, err
|
||||
}
|
||||
|
||||
handshake.ServerAddress, err = readString(reader)
|
||||
if err != nil {
|
||||
return handshake, err
|
||||
}
|
||||
|
||||
if err := binary.Read(reader, binary.BigEndian, &handshake.ServerPort); err != nil {
|
||||
return handshake, err
|
||||
}
|
||||
|
||||
handshake.NextState, err = readVarInt(reader)
|
||||
if err != nil {
|
||||
return handshake, err
|
||||
}
|
||||
|
||||
fmt.Printf("Handshake received: %+v\n", handshake)
|
||||
return handshake, nil
|
||||
}
|
||||
|
||||
func handleStatusRequest(conn net.Conn) {
|
||||
func handleStatusRequest(client *ClientState) {
|
||||
status := StatusResponse{
|
||||
Version: VersionInfo{
|
||||
Name: "1.17.1",
|
||||
Protocol: 756,
|
||||
},
|
||||
Players: PlayerInfo{
|
||||
Max: 100,
|
||||
Online: 5,
|
||||
Sample: []Player{},
|
||||
},
|
||||
Description: Chat{
|
||||
Text: "A Minecraft Server",
|
||||
},
|
||||
Version: VersionInfo{"1.21.4", 769},
|
||||
Players: PlayerInfo{Max: 100, Online: 5, Sample: []Player{}},
|
||||
Description: Chat{Text: "A Minecraft Server"},
|
||||
}
|
||||
|
||||
response, err := json.Marshal(status)
|
||||
@ -177,190 +182,66 @@ func handleStatusRequest(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
w := &Writer{data: make([]byte, 1024)}
|
||||
var packetData bytes.Buffer
|
||||
packetData.WriteByte(StatusResponseID)
|
||||
writeVarInt(&packetData, len(response))
|
||||
packetData.Write(response)
|
||||
|
||||
if err := w.writeVarInt(StatusResponseID); err != nil {
|
||||
fmt.Println("Error writing response ID:", err)
|
||||
return
|
||||
}
|
||||
var responsePacket bytes.Buffer
|
||||
writeVarInt(&responsePacket, packetData.Len())
|
||||
responsePacket.Write(packetData.Bytes())
|
||||
|
||||
if err := w.writeVarInt(len(response)); err != nil {
|
||||
fmt.Println("Error writing response length:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Final Response Packet:", responsePacket.Bytes())
|
||||
|
||||
if err := w.writeString(string(response)); err != nil {
|
||||
fmt.Println("Error writing response:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Send response to client
|
||||
_, err = conn.Write(w.data[:w.cursor])
|
||||
if err != nil {
|
||||
if _, err = client.conn.Write(responsePacket.Bytes()); err != nil {
|
||||
fmt.Println("Error sending response:", err)
|
||||
} else {
|
||||
fmt.Println("Status response sent successfully")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reader) readByte() (byte, error) {
|
||||
if r.cursor >= len(r.data) {
|
||||
return 0, errors.New("EOF")
|
||||
}
|
||||
b := r.data[r.cursor]
|
||||
r.cursor++
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (r *Reader) readVarInt() (int, error) {
|
||||
value := 0
|
||||
position := 0
|
||||
|
||||
func writeVarInt(buf *bytes.Buffer, value int) {
|
||||
for {
|
||||
currentByte, err := r.readByte()
|
||||
temp := byte(value & 0x7F)
|
||||
value >>= 7
|
||||
if value > 0 {
|
||||
temp |= 0x80
|
||||
}
|
||||
buf.WriteByte(temp)
|
||||
if value == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readVarInt(reader *bytes.Reader) (int, error) {
|
||||
value, position := 0, 0
|
||||
for {
|
||||
b, err := reader.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
value |= int(currentByte&SEGMENT_BITS) << position
|
||||
|
||||
if (currentByte & CONTINUE_BIT) == 0 {
|
||||
value |= int(b&0x7F) << position
|
||||
if (b & 0x80) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
position += 7
|
||||
if position >= 32 {
|
||||
return 0, errors.New("VarInt is too big")
|
||||
return 0, errors.New("VarInt too big")
|
||||
}
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (r *Reader) readString() (string, error) {
|
||||
length, err := r.readVarInt()
|
||||
func readString(reader *bytes.Reader) (string, error) {
|
||||
length, err := readVarInt(reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if r.cursor+length > len(r.data) {
|
||||
return "", errors.New("EOF: Reached String unexpectedly")
|
||||
strBuf := make([]byte, length)
|
||||
if _, err := reader.Read(strBuf); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
str := string(r.data[r.cursor : r.cursor+length])
|
||||
r.cursor += length
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func (r *Reader) readUnsignedShort() (uint16, error) {
|
||||
b1, err := r.readByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
b2, err := r.readByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return uint16(b1)<<8 | uint16(b2), nil
|
||||
}
|
||||
|
||||
type Writer struct {
|
||||
data []byte
|
||||
cursor int
|
||||
}
|
||||
|
||||
func (w *Writer) writeByte(b byte) error {
|
||||
if w.cursor >= len(w.data) {
|
||||
return errors.New("EOF")
|
||||
}
|
||||
w.data[w.cursor] = b
|
||||
w.cursor++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Writer) writeVarInt(value int) error {
|
||||
for {
|
||||
temp := byte(value & SEGMENT_BITS)
|
||||
value >>= 7
|
||||
if value != 0 {
|
||||
temp |= CONTINUE_BIT
|
||||
}
|
||||
if err := w.writeByte(temp); err != nil {
|
||||
return err
|
||||
}
|
||||
if value == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Writer) writeString(s string) error {
|
||||
length := len(s)
|
||||
if err := w.writeVarInt(length); err != nil {
|
||||
return err
|
||||
}
|
||||
if w.cursor+length > len(w.data) {
|
||||
return errors.New("EOF")
|
||||
}
|
||||
copy(w.data[w.cursor:], s)
|
||||
w.cursor += length
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeByte(conn net.Conn, b byte) error {
|
||||
_, err := conn.Write([]byte{b})
|
||||
return err
|
||||
}
|
||||
|
||||
func writeVarInt(conn net.Conn, value int) error {
|
||||
var buf [5]byte
|
||||
n := 0
|
||||
for {
|
||||
temp := byte(value & SEGMENT_BITS)
|
||||
value >>= 7
|
||||
if value != 0 {
|
||||
temp |= CONTINUE_BIT
|
||||
}
|
||||
buf[n] = temp
|
||||
n++
|
||||
if value == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
_, err := conn.Write(buf[:n])
|
||||
return err
|
||||
}
|
||||
|
||||
func readHandshakePacket(r *Reader, packet *HandshakePacket) error {
|
||||
// Print the whole packet
|
||||
fmt.Println("Packet: ", r.data)
|
||||
|
||||
var err error
|
||||
packet.ProtocolVersion, err = r.readVarInt()
|
||||
fmt.Println("version: ", packet.ProtocolVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
packet.ServerAddress, err = r.readString()
|
||||
fmt.Println(packet.ServerAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
port, err := r.readUnsignedShort()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
packet.ServerPort = port
|
||||
fmt.Println("Port: ", packet.ServerPort)
|
||||
|
||||
packet.NextState, err = r.readVarInt()
|
||||
fmt.Println("Next state: ", packet.NextState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return string(strBuf), nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user