mirror of
https://github.com/MeowLynxSea/pocketmine-rcon.git
synced 2025-07-09 02:44:38 +00:00
Initial commit.
This commit is contained in:
commit
396c9d5b16
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Michael Bang
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
10
README.md
Normal file
10
README.md
Normal file
@ -0,0 +1,10 @@
|
||||
This is a very simple minecraft (and source engine?) RCON client. See [cli/main.go](cli/main.go) for an example on how to use it.
|
||||
|
||||
# Shortcomings
|
||||
- Long (split) responses aren't handled correctly.
|
||||
- Probably a lot more.
|
||||
|
||||
|
||||
# License
|
||||
See the [LICENSE](LICENSE) file.
|
||||
|
51
cli/main.go
Normal file
51
cli/main.go
Normal file
@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/katnegermis/pocketmine-rcon"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Printf("Usage: ./rcon address password")
|
||||
return
|
||||
}
|
||||
addr := os.Args[1]
|
||||
pass := os.Args[2]
|
||||
|
||||
conn, err := rcon.NewConnection(addr, pass)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Successfully logged in at %s!\n", addr)
|
||||
|
||||
prompt()
|
||||
stdin := bufio.NewReader(os.Stdin)
|
||||
input := ""
|
||||
for {
|
||||
if input, err = stdin.ReadString('\n'); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
input = strings.Trim(input[:len(input)-1], " ")
|
||||
if input == ".exit" {
|
||||
break
|
||||
}
|
||||
if len(input) == 0 {
|
||||
prompt()
|
||||
continue
|
||||
}
|
||||
r := conn.SendCommand(input)
|
||||
fmt.Printf("Server:\n%s\n", r)
|
||||
prompt()
|
||||
}
|
||||
}
|
||||
|
||||
func prompt() {
|
||||
fmt.Print("Enter command:\n>")
|
||||
}
|
118
connection.go
Normal file
118
connection.go
Normal file
@ -0,0 +1,118 @@
|
||||
package rcon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Connection struct {
|
||||
conn net.Conn
|
||||
pass string
|
||||
addr string
|
||||
}
|
||||
|
||||
var uniqueId int32 = 0
|
||||
|
||||
func NewConnection(addr, pass string) (*Connection, error) {
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
c := &Connection{conn: conn, pass: pass, addr: addr}
|
||||
if err := c.auth(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Connection) SendCommand(cmd string) string {
|
||||
c.sendCommand(2, []byte(cmd))
|
||||
pkg := c.readPkg()
|
||||
return string(pkg.Body)
|
||||
}
|
||||
|
||||
func (c *Connection) auth() error {
|
||||
c.sendCommand(3, []byte(c.pass))
|
||||
pkg := c.readPkg()
|
||||
if pkg.Type != 2 || pkg.Id != uniqueId {
|
||||
return errors.New("Incorrect password.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Connection) sendCommand(typ int32, body []byte) {
|
||||
size := int32(4 + 4 + len(body) + 2)
|
||||
uniqueId += 1
|
||||
id := uniqueId
|
||||
|
||||
wtr := binaryReadWriter{ByteOrder: binary.LittleEndian}
|
||||
wtr.Write(size)
|
||||
wtr.Write(id)
|
||||
wtr.Write(typ)
|
||||
wtr.Write(body)
|
||||
wtr.Write([]byte{0x0, 0x0})
|
||||
if wtr.err != nil {
|
||||
log.Fatal(wtr.err)
|
||||
}
|
||||
|
||||
c.conn.Write(wtr.buf.Bytes())
|
||||
}
|
||||
|
||||
func (c *Connection) readPkg() Pkg {
|
||||
const bufSize = 4096
|
||||
b := make([]byte, bufSize)
|
||||
|
||||
// Doesn't handle split messages correctly.
|
||||
read, err := c.conn.Read(b)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
p := Pkg{}
|
||||
rdr := binaryReadWriter{ByteOrder: binary.LittleEndian,
|
||||
buf: bytes.NewBuffer(b)}
|
||||
rdr.Read(&p.Size)
|
||||
rdr.Read(&p.Id)
|
||||
rdr.Read(&p.Type)
|
||||
body := [bufSize - 12]byte{}
|
||||
rdr.Read(&body)
|
||||
if rdr.err != nil {
|
||||
log.Fatal(rdr.err)
|
||||
}
|
||||
p.Body = body[:read-12]
|
||||
return p
|
||||
}
|
||||
|
||||
type Pkg struct {
|
||||
Size int32
|
||||
Id int32
|
||||
Type int32
|
||||
Body []byte
|
||||
_null int16
|
||||
}
|
||||
|
||||
type binaryReadWriter struct {
|
||||
ByteOrder binary.ByteOrder
|
||||
err error
|
||||
buf *bytes.Buffer
|
||||
}
|
||||
|
||||
func (b *binaryReadWriter) Write(v interface{}) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
if b.buf == nil {
|
||||
b.buf = new(bytes.Buffer)
|
||||
}
|
||||
b.err = binary.Write(b.buf, b.ByteOrder, v)
|
||||
}
|
||||
|
||||
func (b *binaryReadWriter) Read(v interface{}) {
|
||||
if b.err != nil || b.buf == nil {
|
||||
return
|
||||
}
|
||||
binary.Read(b.buf, b.ByteOrder, v)
|
||||
}
|
Loading…
Reference in New Issue
Block a user