Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions scripts/generate_cbor_vectors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import json
import cbor
from pathlib import Path

def main():
vectors_dir = Path(__file__).resolve().parent.parent / 'tests' / 'vectors'
json_files = list(vectors_dir.glob('*.json'))
print(f"Found JSON files: {json_files}")

for json_file in json_files:
cbor_file = json_file.with_suffix('.cbor')
print(f"Generating {cbor_file} from {json_file}")

with open(json_file, 'r') as f:
data = json.load(f)

encoded_data = cbor.dumps(data)
print(f"Encoded data for {json_file.name}: {encoded_data}")

with open(cbor_file, 'wb') as f:
f.write(encoded_data)

# Verify the file content
with open(cbor_file, 'rb') as f:
read_data = f.read()
print(f"Read back data for {cbor_file.name}: {read_data}")
assert encoded_data == read_data, f"Verification failed for {cbor_file.name}"

print("CBOR files generated and verified successfully.")

if __name__ == "__main__":
main()
74 changes: 74 additions & 0 deletions src/go/cmd/client/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package main

import (
"crypto/tls"
"crypto/x509"
"example.com/packet"
"fmt"
"io/ioutil"
"log"
)

func main() {
log.Println("Starting Go client...")

cert, err := ioutil.ReadFile("../../python/server.crt")
if err != nil {
log.Fatalf("client: load server cert: %s", err)
}
certPool := x509.NewCertPool()
if ok := certPool.AppendCertsFromPEM(cert); !ok {
log.Fatal("failed to append certs")
}

config := tls.Config{RootCAs: certPool}

conn, err := tls.Dial("tcp", "localhost:8443", &config)
if err != nil {
log.Fatalf("client: dial: %s", err)
}
defer conn.Close()
log.Println("Client connected to server")

// Create and send packet
header := packet.Header{
VersionFlags: 1,
MessageType: 1, // Request
SessionID: 12345,
ChannelID: 67890,
MediaTypeSub: 1, // TEXT
CodecFormat: 1, // UTF-8
SeqNumber: 1,
PriorityQoS: 1,
Extensions: map[string]interface{}{"auth_token": "dummy_token_go"},
}
p := packet.Packet{
Header: header,
Payload: []byte("Hello from Go client!"),
}

reqBytes, err := p.Serialize()
if err != nil {
log.Fatalf("client: serialize error: %s", err)
}

if _, err := conn.Write(reqBytes); err != nil {
log.Fatalf("client: write error: %s", err)
}
log.Println("Sent packet")

// Read response
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
log.Fatalf("client: read error: %s", err)
}
log.Printf("Received %d bytes", n)

respPacket, err := packet.Deserialize(buf[:n])
if err != nil {
log.Fatalf("client: deserialize error: %s", err)
}
fmt.Printf("Received response: %+v\n", respPacket.Header)
fmt.Printf("Payload: %s\n", string(respPacket.Payload))
}
88 changes: 88 additions & 0 deletions src/go/cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
"crypto/tls"
"example.com/packet"
"fmt"
"io"
"log"
"net"
)

func main() {
log.Println("Starting Go server...")

cert, err := tls.LoadX509KeyPair("../../python/server.crt", "../../python/server.key")
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
config := tls.Config{Certificates: []tls.Certificate{cert}}

ln, err := tls.Listen("tcp", ":8443", &config)
if err != nil {
log.Fatalf("server: listen: %s", err)
}
defer ln.Close()

log.Println("Server is listening on port 8443")

for {
conn, err := ln.Accept()
if err != nil {
log.Printf("server: accept: %s", err)
break
}
log.Printf("Accepted connection from %s", conn.RemoteAddr())
go handleConnection(conn)
}
}

func handleConnection(conn net.Conn) {
defer conn.Close()
log.Printf("Handling connection for %s", conn.RemoteAddr())

buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if err != nil {
if err != io.EOF {
log.Printf("server: read: %s", err)
}
break
}
log.Printf("Received %d bytes", n)

p, err := packet.Deserialize(buf[:n])
if err != nil {
log.Printf("server: deserialize error: %s", err)
continue
}
fmt.Printf("Received packet: %+v\n", p.Header)

// Create and send response
responseHeader := packet.Header{
VersionFlags: p.Header.VersionFlags,
MessageType: 2, // Response
SessionID: p.Header.SessionID,
ChannelID: p.Header.ChannelID,
SeqNumber: p.Header.SeqNumber + 1,
}
responsePacket := packet.Packet{
Header: responseHeader,
Payload: []byte("Hello from Go server!"),
}

respBytes, err := responsePacket.Serialize()
if err != nil {
log.Printf("server: serialize error: %s", err)
continue
}

if _, err := conn.Write(respBytes); err != nil {
log.Printf("server: write error: %s", err)
break
}
log.Println("Sent response packet")
}
log.Printf("Connection closed for %s", conn.RemoteAddr())
}
5 changes: 5 additions & 0 deletions src/go/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
module example.com/packet

go 1.20

require (
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
)
4 changes: 4 additions & 0 deletions src/go/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
147 changes: 137 additions & 10 deletions src/go/packet.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,148 @@
package packet

import (
"bytes"
"encoding/binary"
"fmt"
"github.com/fxamacker/cbor/v2"
)

type Header struct {
ID uint32
Version uint16
VersionFlags uint16
MessageType uint8
SessionID uint32
ChannelID uint32
MediaTypeSub uint8
CodecFormat uint8
SeqNumber uint16
PriorityQoS uint8
HeaderLength uint16
PayloadLength uint32
Extensions map[string]interface{}
}

type Packet struct {
Header Header
Payload []byte
Header Header
Payload []byte
}

func (p *Packet) Serialize() []byte {
// TODO: implement serialization
return []byte{}
func (p *Packet) Serialize() ([]byte, error) {
var buf bytes.Buffer

// Serialize extensions to CBOR
extBytes, err := cbor.Marshal(p.Header.Extensions)
if err != nil {
return nil, fmt.Errorf("failed to marshal extensions: %w", err)
}

// Calculate header and payload length
// The fixed header size is 22 bytes
// H(2) + B(1) + I(4) + I(4) + B(1) + B(1) + H(2) + B(1) + H(2) + I(4) = 22
fixedHeaderSize := 22
p.Header.HeaderLength = uint16(fixedHeaderSize + len(extBytes))
p.Header.PayloadLength = uint32(len(p.Payload))

// Write fixed-size header fields
if err := binary.Write(&buf, binary.BigEndian, p.Header.VersionFlags); err != nil {
return nil, err
}
if err := binary.Write(&buf, binary.BigEndian, p.Header.MessageType); err != nil {
return nil, err
}
if err := binary.Write(&buf, binary.BigEndian, p.Header.SessionID); err != nil {
return nil, err
}
if err := binary.Write(&buf, binary.BigEndian, p.Header.ChannelID); err != nil {
return nil, err
}
if err := binary.Write(&buf, binary.BigEndian, p.Header.MediaTypeSub); err != nil {
return nil, err
}
if err := binary.Write(&buf, binary.BigEndian, p.Header.CodecFormat); err != nil {
return nil, err
}
if err := binary.Write(&buf, binary.BigEndian, p.Header.SeqNumber); err != nil {
return nil, err
}
if err := binary.Write(&buf, binary.BigEndian, p.Header.PriorityQoS); err != nil {
return nil, err
}
if err := binary.Write(&buf, binary.BigEndian, p.Header.HeaderLength); err != nil {
return nil, err
}
if err := binary.Write(&buf, binary.BigEndian, p.Header.PayloadLength); err != nil {
return nil, err
}

// Write extensions
if _, err := buf.Write(extBytes); err != nil {
return nil, err
}

// Write payload
if _, err := buf.Write(p.Payload); err != nil {
return nil, err
}

return buf.Bytes(), nil
}

func Deserialize(data []byte) *Packet {
// TODO: implement deserialization
return &Packet{}
func Deserialize(data []byte) (*Packet, error) {
buf := bytes.NewReader(data)
var packet Packet

// Read fixed-size header fields
if err := binary.Read(buf, binary.BigEndian, &packet.Header.VersionFlags); err != nil {
return nil, err
}
if err := binary.Read(buf, binary.BigEndian, &packet.Header.MessageType); err != nil {
return nil, err
}
if err := binary.Read(buf, binary.BigEndian, &packet.Header.SessionID); err != nil {
return nil, err
}
if err := binary.Read(buf, binary.BigEndian, &packet.Header.ChannelID); err != nil {
return nil, err
}
if err := binary.Read(buf, binary.BigEndian, &packet.Header.MediaTypeSub); err != nil {
return nil, err
}
if err := binary.Read(buf, binary.BigEndian, &packet.Header.CodecFormat); err != nil {
return nil, err
}
if err := binary.Read(buf, binary.BigEndian, &packet.Header.SeqNumber); err != nil {
return nil, err
}
if err := binary.Read(buf, binary.BigEndian, &packet.Header.PriorityQoS); err != nil {
return nil, err
}
if err := binary.Read(buf, binary.BigEndian, &packet.Header.HeaderLength); err != nil {
return nil, err
}
if err := binary.Read(buf, binary.BigEndian, &packet.Header.PayloadLength); err != nil {
return nil, err
}

// Read extensions
fixedHeaderSize := 22
extLen := int(packet.Header.HeaderLength) - fixedHeaderSize
if extLen > 0 {
extBytes := make([]byte, extLen)
if _, err := buf.Read(extBytes); err != nil {
return nil, fmt.Errorf("failed to read extensions: %w", err)
}
if err := cbor.Unmarshal(extBytes, &packet.Header.Extensions); err != nil {
return nil, fmt.Errorf("failed to unmarshal extensions: %w", err)
}
}

// Read payload
if packet.Header.PayloadLength > 0 {
packet.Payload = make([]byte, packet.Header.PayloadLength)
if _, err := buf.Read(packet.Payload); err != nil {
return nil, fmt.Errorf("failed to read payload: %w", err)
}
}

return &packet, nil
}
Loading
Loading