Compare commits

..

3 Commits

Author SHA1 Message Date
1b8d01735c Implement inital handshake and receive loop 2026-05-22 14:57:15 +02:00
c5a875be34 Add basic usage example 2026-05-22 14:57:15 +02:00
2ea433f93e Implement Frames 2026-05-22 14:55:49 +02:00
3 changed files with 134 additions and 22 deletions

View File

@@ -19,6 +19,8 @@ type PacketEngine struct {
Ready bool Ready bool
conn net.Conn conn net.Conn
mu sync.Mutex mu sync.Mutex
Messages chan []byte
version string
} }
func WithTimeout(d time.Duration) Option { func WithTimeout(d time.Duration) Option {
@@ -27,7 +29,7 @@ func WithTimeout(d time.Duration) Option {
} }
} }
func NewPacketEngine(address string, opts ...Option) (*PacketEngine, error) { func NewPacketEngine(address string, opts ...Option) *PacketEngine {
defaultCfg := Config{ defaultCfg := Config{
Timeout: 5 * time.Second, Timeout: 5 * time.Second,
} }
@@ -36,11 +38,14 @@ func NewPacketEngine(address string, opts ...Option) (*PacketEngine, error) {
opt(&defaultCfg) opt(&defaultCfg)
} }
return &PacketEngine{ pe := PacketEngine{
address: address, address: address,
cfg: defaultCfg, cfg: defaultCfg,
Ready: false, Ready: false,
}, nil Messages: make(chan []byte),
}
return &pe
} }
func (pe *PacketEngine) Connect() error { func (pe *PacketEngine) Connect() error {
@@ -50,6 +55,7 @@ func (pe *PacketEngine) Connect() error {
} }
pe.conn = conn pe.conn = conn
fmt.Println("Connected to", pe.address) fmt.Println("Connected to", pe.address)
go pe.receiveLoop()
return nil return nil
} }
@@ -64,3 +70,37 @@ func (pe *PacketEngine) Disconnect() error {
return nil return nil
} }
func (pe *PacketEngine) Send(data []byte) error {
_, err := pe.conn.Write(data)
return err
}
func (pe *PacketEngine) receiveLoop() {
defer close(pe.Messages)
for {
buf := make([]byte, 1024)
n, err := pe.conn.Read(buf)
if err != nil {
// FIXME: handle error
panic(err)
}
data := buf[:n]
pe.Messages <- data
}
}
func (pe *PacketEngine) Version() string {
if pe.conn == nil {
return ""
}
if pe.version != "" {
return pe.version
}
return fmt.Sprintf("%d.%d")
}

38
cmd/basic_usage/main.go Normal file
View File

@@ -0,0 +1,38 @@
package main
import (
"fmt"
"os"
)
import "git.smith.eu/m/go-agwpe"
func main() {
engine := agwpe.NewPacketEngine("172.16.0.4:8000")
err := engine.Connect()
if err != nil {
fmt.Printf("Error connecting: %v\n", err)
}
defer engine.Disconnect()
version := engine.Version()
fmt.Printf("AGWPE version: %s\n", version)
frame := agwpe.NewVersionFrame()
frameData, err := frame.Serialize()
if err != nil {
fmt.Fprintf(os.Stderr, "Serialization error: %v\n", err)
}
err = engine.Send(frameData)
if err != nil {
fmt.Println("Error:", err)
}
for msg := range engine.Messages {
major_verion := (uint16(msg[37]) << 8) | uint16(msg[36])
minor_verion := (uint16(msg[41]) << 8) | uint16(msg[40])
fmt.Printf("AGWPE version: %d.%d\n", major_verion, minor_verion)
}
}

View File

@@ -2,9 +2,10 @@ package agwpe
import ( import (
"encoding/binary" "encoding/binary"
"fmt"
) )
type FrameHeader struct { type Header struct {
Port byte Port byte
Reserved0 [3]byte Reserved0 [3]byte
DataKind byte DataKind byte
@@ -17,19 +18,52 @@ type FrameHeader struct {
User [4]byte User [4]byte
} }
func (f *FrameHeader) Serialize() []byte { func serializeHeader(h Header) []byte {
buf := make([]byte, 36) data := make([]byte, 36)
buf[0] = f.Port data[0] = h.Port
// Ignore reserved bytes 1 to 3 // Ignore reserved bytes 1 to 3
buf[4] = f.DataKind data[4] = h.DataKind
// Ignore reserved byte 5 // Ignore reserved byte 5
buf[6] = f.PID data[6] = h.PID
// Ignore reserved byte 7 // Ignore reserved byte 7
copy(buf[8:18], f.CallFrom[:]) copy(data[8:18], h.CallFrom[:])
copy(buf[18:28], f.CallTo[:]) copy(data[18:28], h.CallTo[:])
binary.LittleEndian.PutUint32(buf[28:32], f.DataLen) binary.LittleEndian.PutUint32(data[28:32], h.DataLen)
copy(buf[32:36], f.User[:]) copy(data[32:36], h.User[:])
return buf return data
}
type Frame interface {
Header() Header
}
type VersionFrame struct {
header Header
major, minor uint16
}
func NewVersionFrame() *VersionFrame {
return &VersionFrame{
header: Header{
Port: 0x01,
DataKind: 0x52},
}
}
func (f *VersionFrame) Header() Header {
return f.header
}
func (f *VersionFrame) Serialize() ([]byte, error) {
data := serializeHeader(f.header)
return data, nil
}
func (f *VersionFrame) parseVersion(data []byte) {
f.major = (uint16(data[37]) << 8) | uint16(data[36])
f.minor = (uint16(data[41]) << 8) | uint16(data[40])
fmt.Printf("AGWPE version: %d.%d\n", f.major, f.minor)
} }