WIP: Update struct decode and encode #2
@ -76,13 +76,13 @@ func (client *Client) Setup() error {
|
||||
}
|
||||
|
||||
type toWr struct {
|
||||
Proto uint8
|
||||
Proto proto.Protoc
|
||||
To netip.AddrPort
|
||||
tun *Client
|
||||
}
|
||||
|
||||
func (t toWr) Write(w []byte) (int, error) {
|
||||
err := structcode.NewEncode(t.tun.Conn, proto.Request{
|
||||
data := proto.Request{
|
||||
DataTX: &proto.ClientData{
|
||||
Data: w,
|
||||
Client: proto.Client{
|
||||
@ -90,21 +90,23 @@ func (t toWr) Write(w []byte) (int, error) {
|
||||
Proto: t.Proto,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err == nil {
|
||||
return len(w), nil
|
||||
}
|
||||
return 0, err
|
||||
d, _ := json.Marshal(data)
|
||||
fmt.Println(string(d))
|
||||
if err := structcode.NewEncode(t.tun.Conn, data); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(w), nil
|
||||
}
|
||||
|
||||
func (tun *Client) GetTargetWrite(Proto uint8, To netip.AddrPort) io.Writer {
|
||||
func (tun *Client) GetTargetWrite(Proto proto.Protoc, To netip.AddrPort) io.Writer {
|
||||
return &toWr{Proto: Proto, To: To, tun: tun}
|
||||
}
|
||||
|
||||
func (client *Client) handlers() {
|
||||
var lastPing int64 = 0
|
||||
var lastPing time.Time = time.Date(0, 0, 0, 0, 0, 0, 0, time.Local)
|
||||
for {
|
||||
if time.Now().UnixMilli()-lastPing > 3_000 {
|
||||
if time.Now().UnixMilli()-lastPing.UnixMilli() > 3_000_000 {
|
||||
var req proto.Request
|
||||
req.Ping = new(time.Time)
|
||||
*req.Ping = time.Now()
|
||||
@ -125,7 +127,7 @@ func (client *Client) handlers() {
|
||||
fmt.Println(string(d))
|
||||
|
||||
if res.Pong != nil {
|
||||
lastPing = res.Pong.UnixMilli()
|
||||
lastPing = *res.Pong
|
||||
continue
|
||||
}
|
||||
if res.Unauthorized || res.NotListened {
|
||||
|
@ -3,9 +3,11 @@ package server
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
|
||||
"sirherobrine23.org/Minecraft-Server/go-pproxit/server"
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/names"
|
||||
@ -13,6 +15,7 @@ import (
|
||||
|
||||
type serverCalls struct {
|
||||
XormEngine *xorm.Engine
|
||||
Locker sync.Locker
|
||||
}
|
||||
|
||||
type User struct {
|
||||
@ -25,12 +28,12 @@ type User struct {
|
||||
}
|
||||
|
||||
type Tun struct {
|
||||
ID int64 `xorm:"pk"` // Tunnel ID
|
||||
User int64 `xorm:"notnull"` // Agent ID
|
||||
Token []byte `xorm:"blob notnull unique"` // Tunnel Token
|
||||
Proto uint8 `xorm:"default 3"` // Proto accept
|
||||
TPCListen uint16 // Port listen TCP agent
|
||||
UDPListen uint16 // Port listen UDP agent
|
||||
ID int64 `xorm:"pk"` // Tunnel ID
|
||||
User int64 `xorm:"notnull"` // Agent ID
|
||||
Token []byte `xorm:"blob notnull unique"` // Tunnel Token
|
||||
Proto proto.Protoc `xorm:"default 3"` // Proto accept
|
||||
TPCListen uint16 // Port listen TCP agent
|
||||
UDPListen uint16 // Port listen UDP agent
|
||||
}
|
||||
|
||||
type Ping struct {
|
||||
@ -53,7 +56,7 @@ type RTX struct {
|
||||
Client netip.AddrPort
|
||||
TXSize int
|
||||
RXSize int
|
||||
Proto uint8
|
||||
Proto proto.Protoc
|
||||
}
|
||||
|
||||
func NewCall(DBConn string) (call *serverCalls, err error) {
|
||||
@ -61,6 +64,7 @@ func NewCall(DBConn string) (call *serverCalls, err error) {
|
||||
if call.XormEngine, err = xorm.NewEngine("sqlite", DBConn); err != nil {
|
||||
return
|
||||
}
|
||||
call.Locker = &sync.Mutex{}
|
||||
call.XormEngine.SetMapper(names.SameMapper{})
|
||||
session := call.XormEngine.NewSession()
|
||||
defer session.Close()
|
||||
@ -75,11 +79,13 @@ func NewCall(DBConn string) (call *serverCalls, err error) {
|
||||
type TunCallbcks struct {
|
||||
tunID int64
|
||||
XormEngine *xorm.Engine
|
||||
Locker sync.Locker
|
||||
}
|
||||
|
||||
func (tun *TunCallbcks) AgentShutdown(onTime time.Time) {}
|
||||
|
||||
func (*TunCallbcks) AgentShutdown(onTime time.Time) {}
|
||||
func (tun *TunCallbcks) BlockedAddr(AddrPort string) bool {
|
||||
tun.Locker.Lock()
|
||||
defer tun.Locker.Unlock()
|
||||
var addr = AddrBlocked{Address: AddrPort, TunID: tun.tunID}
|
||||
ok, err := tun.XormEngine.Get(&addr)
|
||||
if err != nil {
|
||||
@ -102,6 +108,8 @@ func (tun *TunCallbcks) BlockedAddr(AddrPort string) bool {
|
||||
}
|
||||
|
||||
func (tun *TunCallbcks) AgentPing(agent, server time.Time) {
|
||||
tun.Locker.Lock()
|
||||
defer tun.Locker.Unlock()
|
||||
c, _ := tun.XormEngine.Count(Ping{})
|
||||
tun.XormEngine.InsertOne(&Ping{
|
||||
ID: c,
|
||||
@ -111,7 +119,9 @@ func (tun *TunCallbcks) AgentPing(agent, server time.Time) {
|
||||
})
|
||||
}
|
||||
|
||||
func (tun *TunCallbcks) RegisterRX(client netip.AddrPort, Size int, Proto uint8) {
|
||||
func (tun *TunCallbcks) RegisterRX(client netip.AddrPort, Size int, Proto proto.Protoc) {
|
||||
tun.Locker.Lock()
|
||||
defer tun.Locker.Unlock()
|
||||
tun.XormEngine.InsertOne(&RTX{
|
||||
TunID: tun.tunID,
|
||||
Client: client,
|
||||
@ -120,7 +130,9 @@ func (tun *TunCallbcks) RegisterRX(client netip.AddrPort, Size int, Proto uint8)
|
||||
TXSize: 0,
|
||||
})
|
||||
}
|
||||
func (tun *TunCallbcks) RegisterTX(client netip.AddrPort, Size int, Proto uint8) {
|
||||
func (tun *TunCallbcks) RegisterTX(client netip.AddrPort, Size int, Proto proto.Protoc) {
|
||||
tun.Locker.Lock()
|
||||
defer tun.Locker.Unlock()
|
||||
tun.XormEngine.InsertOne(&RTX{
|
||||
TunID: tun.tunID,
|
||||
Client: client,
|
||||
@ -142,6 +154,6 @@ func (caller *serverCalls) AgentAuthentication(Token []byte) (server.TunnelInfo,
|
||||
Proto: tun.Proto,
|
||||
TCPPort: tun.TPCListen,
|
||||
UDPPort: tun.UDPListen,
|
||||
Callbacks: &TunCallbcks{tunID: tun.ID, XormEngine: caller.XormEngine},
|
||||
Callbacks: &TunCallbcks{tunID: tun.ID, XormEngine: caller.XormEngine, Locker: caller.Locker},
|
||||
}, nil
|
||||
}
|
||||
|
@ -64,6 +64,22 @@ func decodeRecursive(r io.Reader, reflectValue reflect.Value) error {
|
||||
}
|
||||
reflectValue.Set(reflect.ValueOf(data).Elem())
|
||||
case reflect.Interface:
|
||||
case reflect.Map:
|
||||
mapTypeof := reflectValue.Type()
|
||||
reflectValue.Set(reflect.MakeMap(mapTypeof))
|
||||
var size uint64
|
||||
if err := binary.Read(r, binary.BigEndian, &size); err != nil {
|
||||
return err
|
||||
}
|
||||
for range size {
|
||||
key, value := reflect.New(mapTypeof.Key()).Elem(), reflect.New(mapTypeof.Elem()).Elem()
|
||||
if err := decodeRecursive(r, key); err != nil {
|
||||
return err
|
||||
} else if err := decodeRecursive(r, value); err != nil {
|
||||
return err
|
||||
}
|
||||
reflectValue.SetMapIndex(key, value)
|
||||
}
|
||||
case reflect.Struct:
|
||||
if ok, err := decodeTypeof(r, reflectValue); ok {
|
||||
return err
|
||||
|
@ -39,6 +39,18 @@ func encodeRecursive(w io.Writer, reflectValue reflect.Value) error {
|
||||
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return binary.Write(w, binary.BigEndian, reflectValue.Interface())
|
||||
case reflect.Interface:
|
||||
case reflect.Map:
|
||||
if err := binary.Write(w, binary.BigEndian, uint64(reflectValue.Len())); err != nil {
|
||||
return err
|
||||
}
|
||||
inter := reflectValue.MapRange()
|
||||
for inter.Next() {
|
||||
if err := encodeRecursive(w, inter.Key()); err != nil {
|
||||
return err
|
||||
} else if err := encodeRecursive(w, inter.Value()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
if ok, err := encodeTypeof(w, reflectValue); ok {
|
||||
return err
|
||||
|
@ -2,8 +2,11 @@ package structcode
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
mathrand "math/rand/v2"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"testing"
|
||||
@ -12,7 +15,67 @@ import (
|
||||
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
|
||||
)
|
||||
|
||||
type mapTest map[string]mapStr
|
||||
type mapStr struct {
|
||||
Text string
|
||||
Blob []byte
|
||||
}
|
||||
|
||||
func randomBuff(size int) []byte {
|
||||
buff := make([]byte, size)
|
||||
_, err := rand.Read(buff)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buff
|
||||
}
|
||||
|
||||
func TestSerelelize(t *testing.T) {
|
||||
t.Run("Map", func(t *testing.T) {
|
||||
var err error
|
||||
var waiter sync.WaitGroup
|
||||
var enc, dec mapTest
|
||||
enc = mapTest{}
|
||||
enc["Test"] = mapStr{"Golang is best", []byte{5, 14, 22, 13}}
|
||||
for i := range mathrand.IntN(20) {
|
||||
enc["Rand"+fmt.Sprint(i)] = mapStr{string(randomBuff(14)), randomBuff(64)}
|
||||
}
|
||||
|
||||
waiter.Add(2)
|
||||
r, w := io.Pipe()
|
||||
go func() {
|
||||
defer waiter.Done()
|
||||
if err = NewDecode(r, &dec); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer waiter.Done()
|
||||
if err = NewEncode(w, enc); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
waiter.Wait()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for k, v := range enc {
|
||||
if d, ok := dec[k]; ok {
|
||||
if v.Text != d.Text {
|
||||
t.Errorf("text from decode not exists or mismatch (%q), Encode %q, Decode %q", k, v.Text, d.Text)
|
||||
return
|
||||
} else if !bytes.Equal(v.Blob, d.Blob) {
|
||||
t.Errorf("blob from decode not exists or mismatch (%q), Encode %s, Decode %s", k, hex.EncodeToString(v.Blob), hex.EncodeToString(d.Blob))
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
t.Errorf("key not exists in decode (%q)", k)
|
||||
return
|
||||
}
|
||||
})
|
||||
t.Run("Response", func(t *testing.T) {
|
||||
var err error
|
||||
var encodeRes, decodeRes proto.Response
|
||||
|
@ -6,22 +6,36 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ProtoBoth uint8 = iota // TCP+UDP Protocol
|
||||
ProtoTCP // TCP Protocol
|
||||
ProtoUDP // UDP Protocol
|
||||
ProtoBoth Protoc = iota // TCP+UDP Protocol
|
||||
ProtoTCP // TCP Protocol
|
||||
ProtoUDP // UDP Protocol
|
||||
|
||||
DataSize uint64 = 10_000 // Default listener data recive and send
|
||||
PacketSize uint64 = 800 // Packet to without data only requests and response headers
|
||||
PacketDataSize uint64 = DataSize + PacketSize // Header and Data request/response
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidBody error = errors.New("invalid body, check request/response")
|
||||
)
|
||||
var ErrInvalidBody error = errors.New("invalid body, check request/response")
|
||||
|
||||
type Protoc uint8 // Net protocol support
|
||||
|
||||
func (pr Protoc) MarshalText() ([]byte, error) { return []byte(pr.String()), nil }
|
||||
func (pr Protoc) String() string {
|
||||
switch pr {
|
||||
case ProtoBoth:
|
||||
return "TCP + UDP"
|
||||
case ProtoTCP:
|
||||
return "TCP"
|
||||
case ProtoUDP:
|
||||
return "UDP"
|
||||
default:
|
||||
return "Invalid proto"
|
||||
}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
Client netip.AddrPort // Client address and port
|
||||
Proto uint8 // Protocol to close (proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth)
|
||||
Proto Protoc // Protocol to close (proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth)
|
||||
}
|
||||
|
||||
type ClientData struct {
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type AgentInfo struct {
|
||||
Protocol uint8 // Proto supported (proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth)
|
||||
Protocol Protoc // Proto supported (proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth)
|
||||
UDPPort, TCPPort uint16 // Controller port listened
|
||||
AddrPort netip.AddrPort // request address and port
|
||||
}
|
||||
|
@ -15,17 +15,17 @@ import (
|
||||
)
|
||||
|
||||
type TunnelCall interface {
|
||||
BlockedAddr(AddrPort string) bool // Ignore request from this address
|
||||
AgentPing(agent, server time.Time) // Register ping to Agent
|
||||
AgentShutdown(onTime time.Time) // Agend end connection
|
||||
RegisterRX(client netip.AddrPort, Size int, Proto uint8) // Register Recived data from client
|
||||
RegisterTX(client netip.AddrPort, Size int, Proto uint8) // Register Transmitted data from client
|
||||
BlockedAddr(AddrPort string) bool // Ignore request from this address
|
||||
AgentPing(agent, server time.Time) // Register ping to Agent
|
||||
AgentShutdown(onTime time.Time) // Agend end connection
|
||||
RegisterRX(client netip.AddrPort, Size int, Proto proto.Protoc) // Register Recived data from client
|
||||
RegisterTX(client netip.AddrPort, Size int, Proto proto.Protoc) // Register Transmitted data from client
|
||||
}
|
||||
|
||||
type TunnelInfo struct {
|
||||
Proto uint8 // Protocol listen tunnel, use proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth
|
||||
UDPPort, TCPPort uint16 // Port to Listen UDP and TCP listeners
|
||||
Callbacks TunnelCall // Tunnel Callbacks
|
||||
Proto proto.Protoc // Protocol listen tunnel, use proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth
|
||||
UDPPort, TCPPort uint16 // Port to Listen UDP and TCP listeners
|
||||
Callbacks TunnelCall // Tunnel Callbacks
|
||||
}
|
||||
|
||||
type Tunnel struct {
|
||||
@ -65,7 +65,7 @@ func (tun *Tunnel) send(res proto.Response) error {
|
||||
}
|
||||
|
||||
type toWr struct {
|
||||
Proto uint8
|
||||
Proto proto.Protoc
|
||||
To netip.AddrPort
|
||||
tun *Tunnel
|
||||
}
|
||||
@ -87,7 +87,7 @@ func (t toWr) Write(w []byte) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
func (tun *Tunnel) GetTargetWrite(Proto uint8, To netip.AddrPort) io.Writer {
|
||||
func (tun *Tunnel) GetTargetWrite(Proto proto.Protoc, To netip.AddrPort) io.Writer {
|
||||
return &toWr{Proto: Proto, To: To, tun: tun}
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ func (tun *Tunnel) Setup() {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
return
|
||||
}
|
||||
d, _ := json.MarshalIndent(req, "", " ")
|
||||
d, _ := json.Marshal(req)
|
||||
fmt.Println(string(d))
|
||||
|
||||
if req.AgentAuth != nil {
|
||||
|
Reference in New Issue
Block a user