Skip to content

Commit

Permalink
Merge pull request #36 from alteamc/dev
Browse files Browse the repository at this point in the history
v2.2.0
  • Loading branch information
dreamscached authored Aug 10, 2022
2 parents a8ad5fa + 097c107 commit 1c31aba
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 163 deletions.
2 changes: 1 addition & 1 deletion MIGRATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
MineQuery is in active development since its very release, and occasionally, newer
versions of it may introduce changes that might be breaking to existing codebase.

This page will help you migrating your code in order to adapt to changes.
This page will help you migrate your code in order to adapt to changes.

## From v2.0.x

Expand Down
83 changes: 2 additions & 81 deletions io.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package minequery

import (
"bytes"
"encoding/binary"
"io"

"golang.org/x/text/encoding/unicode"
Expand All @@ -13,28 +12,11 @@ var (
utf16BEDecoder = unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM).NewDecoder()
)

type byteReader struct {
reader io.Reader
}

func newByteReader(reader io.Reader) byteReader {
return byteReader{reader}
}

func (r byteReader) ReadByte() (byte, error) {
byteArr := make([]byte, 1)
if _, err := r.reader.Read(byteArr); err != nil {
return 0, err
}
return byteArr[0], nil
}

func readAllUntilZero(reader io.Reader) ([]byte, error) {
br := newByteReader(reader)
func readAllUntilZero(reader io.ByteReader) ([]byte, error) {
buf := &bytes.Buffer{}

for {
b, err := br.ReadByte()
b, err := reader.ReadByte()
if err != nil {
if err == io.EOF {
return buf.Bytes(), nil
Expand All @@ -49,64 +31,3 @@ func readAllUntilZero(reader io.Reader) ([]byte, error) {
}
}
}

func writeBytes(writer io.Writer, bytes []byte) error {
_, err := writer.Write(bytes)
return err
}

func writeBuffer(writer io.Writer, buffer *bytes.Buffer) error {
_, err := buffer.WriteTo(writer)
return err
}

func writeByte(writer io.Writer, c byte) error {
_, err := writer.Write([]byte{c})
return err
}

func readByte(reader io.Reader) (byte, error) {
byteArr := make([]byte, 1)
if _, err := reader.Read(byteArr); err != nil {
return 0, err
}
return byteArr[0], nil
}

func writeUShort(writer io.Writer, value uint16) error {
return binary.Write(writer, binary.BigEndian, value)
}

func readUShort(reader io.Reader) (uint16, error) {
var value uint16
if err := binary.Read(reader, binary.BigEndian, &value); err != nil {
return 0, err
}
return value, nil
}

func writeUInt(writer io.Writer, value uint32) error {
return binary.Write(writer, binary.BigEndian, value)
}

func writeVarInt(writer io.Writer, value int32) error {
intBytes := make([]byte, binary.MaxVarintLen32)
written := binary.PutVarint(intBytes, int64(value))
_, err := writer.Write(intBytes[:written])
return err
}

func writeUVarInt(writer io.Writer, value uint32) error {
intBytes := make([]byte, binary.MaxVarintLen32)
written := binary.PutUvarint(intBytes, uint64(value))
_, err := writer.Write(intBytes[:written])
return err
}

func readUVarInt(reader io.Reader) (uint32, error) {
value, err := binary.ReadUvarint(newByteReader(reader))
if err != nil {
return 0, err
}
return uint32(value), nil
}
41 changes: 4 additions & 37 deletions ping_14.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import (
"strings"
)

var ping14PingPacket = []byte{0xfe}
var ping14PingPacket = []byte{0xfe, 0x01}

const (
ping14ResponsePacketID byte = 0xff
ping14ResponsePayloadFieldSeparator = "§"
ping14ResponsePayloadFieldSeparator = "§"
)

// Status14 holds status response returned by 1.4 to 1.6 (exclusively) Minecraft servers.
Expand Down Expand Up @@ -44,7 +43,7 @@ func (p *Pinger) Ping14(host string, port int) (*Status14, error) {
}

// Read status response (note: uses the same packet reading approach as 1.4)
payload, err := p.ping14ReadResponsePayload(conn)
payload, err := p.pingBeta18ReadResponsePacket(conn)
if err != nil {
return nil, fmt.Errorf("could not read response packet: %w", err)
}
Expand All @@ -62,42 +61,10 @@ func (p *Pinger) Ping14(host string, port int) (*Status14, error) {

func (p *Pinger) ping14WritePingPacket(writer io.Writer) error {
// Write 2-byte FE 01 ping packet
err := writeBytes(writer, ping14PingPacket)
_, err := writer.Write(ping14PingPacket)
return err
}

func (p *Pinger) ping14ReadResponsePayload(reader io.Reader) ([]byte, error) {
// Read packet type, return error if it isn't FF kick packet
id, err := readByte(reader)
if err != nil {
return nil, err
} else if id != ping14ResponsePacketID {
return nil, fmt.Errorf("expected packet ID %#x, but instead got %#x", ping16ResponsePacketID, id)
}

// Read packet length, return error if it isn't readable as unsigned short
// Worth noting that this needs to be multiplied by two further on (for encoding reasons, most probably)
length, err := readUShort(reader)
if err != nil {
return nil, err
}

// Read remainder of the status packet as raw bytes
// This is a UTF-16BE string separated by § (paragraph sign)
payload := bytes.NewBuffer(make([]byte, 0, length*2))
if _, err = io.CopyN(payload, reader, int64(length*2)); err != nil {
return nil, err
}

decoded, err := utf16BEDecoder.Bytes(payload.Bytes())
if err != nil {
return nil, err
}

// Return UTF16-BE decoder with data as input
return decoded, nil
}

// Response processing

func (p *Pinger) ping14ParseResponsePayload(payload []byte) (*Status14, error) {
Expand Down
19 changes: 10 additions & 9 deletions ping_16.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package minequery

import (
"bytes"
"encoding/binary"
"fmt"
"io"
"strconv"
Expand Down Expand Up @@ -452,7 +453,7 @@ func (p *Pinger) Ping16(host string, port int) (*Status16, error) {
}

// Read status response (note: uses the same packet reading approach as 1.4)
payload, err := p.ping14ReadResponsePayload(conn)
payload, err := p.pingBeta18ReadResponsePacket(conn)
if err != nil {
return nil, fmt.Errorf("could not read response packet: %w", err)
}
Expand All @@ -473,29 +474,29 @@ func (p *Pinger) ping16WritePingPacket(writer io.Writer, protocol byte, host str
packet := bytes.NewBuffer(make([]byte, 0, 64))

// Write hardcoded (it doesn't change ever) packet header
_ = writeBytes(packet, ping16PingPacketHeader)
packet.Write(ping16PingPacketHeader)

// Encode hostname to UTF16BE and store in buffer to calculate length further on
hostnameBytes := &bytes.Buffer{}
if _, err := utf16BEEncoder.Writer(hostnameBytes).Write([]byte(host)); err != nil {
hb := &bytes.Buffer{}
if _, err := utf16BEEncoder.Writer(hb).Write([]byte(host)); err != nil {
return err
}

// Write packet length (7 + length of hostname string)
_ = writeUShort(packet, uint16(7+hostnameBytes.Len()))
_ = binary.Write(packet, binary.BigEndian, uint16(7+hb.Len()))

// Get preferred protocol version and fallback to Ping16ProtocolVersion162 if not set
// and write it to packet
_ = writeByte(packet, protocol)
packet.WriteByte(protocol)

// Write hostname string length
_ = writeUShort(packet, uint16(len(host)))
_ = binary.Write(packet, binary.BigEndian, uint16(len(host)))

// Write hostname string
_ = writeBuffer(packet, hostnameBytes)
_, _ = hb.WriteTo(packet)

// Write target server port
_ = writeUInt(packet, uint32(port))
_ = binary.Write(packet, binary.BigEndian, uint32(port))

_, err := packet.WriteTo(writer)
return err
Expand Down
68 changes: 41 additions & 27 deletions ping_17.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package minequery
import (
"bytes"
"encoding/base64"
"encoding/binary"
"encoding/json"
"fmt"
"image"
Expand Down Expand Up @@ -1690,8 +1691,9 @@ func (s *Status17) DescriptionText() string {
case []interface{}:
// If component is a slice, push its items to stack in reverse order
// (so that they are processed in natural order because stack is LIFO)
for i := len(current.([]interface{})) - 1; i >= 0; i-- {
componentStack.Push(current.([]interface{})[i])
current := current.([]interface{})
for i := len(current) - 1; i >= 0; i-- {
componentStack.Push(current[i])
}

case map[string]interface{}:
Expand Down Expand Up @@ -1766,46 +1768,48 @@ func (p *Pinger) Ping17(host string, port int) (*Status17, error) {

func (p *Pinger) ping17WritePacket(writer io.Writer, packetID uint32, payloadData []byte) error {
// Allocate payload buffer of size = 5 (payload length field) + payload length
payloadBuffer := bytes.NewBuffer(make([]byte, 0, 5+len(payloadData)))
pb := bytes.NewBuffer(make([]byte, 0, 5+len(payloadData)))

// Write packet ID as unsigned VarInt to content buffer
_ = writeUVarInt(payloadBuffer, packetID)
b := make([]byte, 5)
pb.Write(b[:binary.PutUvarint(b, uint64(packetID))])

// Copy packet data to content buffer
_, _ = payloadBuffer.Write(payloadData)
_, _ = pb.Write(payloadData)

// Allocate packet buffer of size = 5 (packet ID) + payload length
packet := bytes.NewBuffer(make([]byte, 0, 5+payloadBuffer.Len()))
packet := bytes.NewBuffer(make([]byte, 0, 5+pb.Len()))

// Write packet data length to packet buffer as unsigned VarInt
_ = writeUVarInt(packet, uint32(payloadBuffer.Len()))
// Write packet data length to packet buffer unsigned VarInt
packet.Write(b[:binary.PutUvarint(b, uint64(pb.Len()))])

// Write content buffer to packet buffer
_, _ = payloadBuffer.WriteTo(packet)
_, _ = pb.WriteTo(packet)

_, err := packet.WriteTo(writer)
return err
}

func (p *Pinger) ping17WriteHandshakePacket(writer io.Writer, protocol int32, host string, port int) error {
buffer := bytes.NewBuffer(make([]byte, 0, 32))
packet := bytes.NewBuffer(make([]byte, 0, 32))

// Write protocol version as VarInt
_ = writeVarInt(buffer, protocol)
b := make([]byte, 5)
packet.Write(b[:binary.PutVarint(b, int64(protocol))])

// Write length of hostname string as unsigned VarInt
_ = writeUVarInt(buffer, uint32(len(host)))
packet.Write(b[:binary.PutUvarint(b, uint64(len(host)))])

// Write hostname string as byte array
_ = writeBytes(buffer, []byte(host))
packet.Write([]byte(host))

// Write port as unsigned short
_ = writeUShort(buffer, uint16(port))
_ = binary.Write(packet, binary.BigEndian, uint16(port))

// Write next state as unsigned VarInt
_ = writeUVarInt(buffer, ping17NextStateStatus)
packet.Write(b[:binary.PutUvarint(b, uint64(ping17NextStateStatus))])

return p.ping17WritePacket(writer, ping17HandshakePacketID, buffer.Bytes())
return p.ping17WritePacket(writer, ping17HandshakePacketID, packet.Bytes())
}

func (p *Pinger) ping17WriteStatusRequestPacket(writer io.Writer) error {
Expand All @@ -1814,39 +1818,49 @@ func (p *Pinger) ping17WriteStatusRequestPacket(writer io.Writer) error {
}

func (p *Pinger) ping17ReadStatusResponsePacketPayload(reader io.Reader) ([]byte, error) {
// Allocate buffer of 5 bytes (VarInt maximum length) and read packet length
lb := make([]byte, 5)
ln, err := reader.Read(lb)
if err != nil {
return nil, err
}
lr := bytes.NewReader(lb)

// Read packet length as unsigned VarInt
packetLength, err := readUVarInt(reader)
pl, err := binary.ReadUvarint(lr)
if err != nil {
return nil, err
}

// Read entire packet to a buffer
packet := bytes.NewBuffer(make([]byte, 0, packetLength))
if _, err = io.CopyN(packet, reader, int64(packetLength)); err != nil {
pb := bytes.NewBuffer(make([]byte, 0, pl))
pb.Write(lb[ln-lr.Len() : ln])
if _, err = io.CopyN(pb, reader, int64(pl)-int64(lr.Len())); err != nil {
return nil, err
}
pr := bytes.NewReader(pb.Bytes())

// Read packet ID as unsigned VarInt
id, err := readUVarInt(packet)
id, err := binary.ReadUvarint(pr)
if err != nil {
return nil, err
} else if id != ping17StatusResponsePacketID {
} else if uint32(id) != ping17StatusResponsePacketID {
return nil, fmt.Errorf("expected packet ID %#x, but instead got %#x", ping17StatusResponsePacketID, id)
}

// Read JSON data length as unsigned VarInt
dataLength, err := readUVarInt(packet)
// Read status payload length
dl, err := binary.ReadUvarint(pr)
if err != nil {
return nil, err
}

// Read JSON data to a buffer
payload := bytes.NewBuffer(make([]byte, 0, dataLength))
if _, err = io.CopyN(payload, packet, int64(dataLength)); err != nil {
// Read packet payload
db := bytes.NewBuffer(make([]byte, 0, dl))
if _, err = io.CopyN(db, pr, int64(dl)); err != nil {
return nil, err
}

return payload.Bytes(), nil
return db.Bytes(), nil
}

// Response processing
Expand Down
Loading

0 comments on commit 1c31aba

Please sign in to comment.