89 lines
1.6 KiB
Go
89 lines
1.6 KiB
Go
|
package packer
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
type Parser struct {
|
||
|
ctx context.Context
|
||
|
handler Handler
|
||
|
newConns chan *Conn
|
||
|
conns map[string]*Conn
|
||
|
state ParserState
|
||
|
parseState State
|
||
|
dataReady chan struct{}
|
||
|
data []byte
|
||
|
written int
|
||
|
}
|
||
|
|
||
|
type ParserState struct {
|
||
|
written int
|
||
|
version byte
|
||
|
headerLen int
|
||
|
header []byte
|
||
|
payloadLen int
|
||
|
addr Addr
|
||
|
payloadWritten int
|
||
|
}
|
||
|
|
||
|
type State int
|
||
|
|
||
|
const (
|
||
|
V1 byte = 255 - (1 + iota)
|
||
|
V2
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
VersionState State = 0
|
||
|
)
|
||
|
|
||
|
func NewParser(ctx context.Context, handler Handler) *Parser {
|
||
|
return &Parser{
|
||
|
ctx: ctx,
|
||
|
conns: make(map[string]*Conn),
|
||
|
newConns: make(chan *Conn, 2), // Buffered to make testing easier
|
||
|
dataReady: make(chan struct{}, 2),
|
||
|
data: []byte{},
|
||
|
handler: handler,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Handler interface {
|
||
|
WriteMessage(Addr, []byte)
|
||
|
}
|
||
|
|
||
|
// Write receives tunnel data and creates or writes to connections
|
||
|
func (p *Parser) Write(b []byte) (int, error) {
|
||
|
if len(b) < 1 {
|
||
|
return 0, errors.New("developer error: wrote 0 bytes")
|
||
|
}
|
||
|
|
||
|
// so that we can overwrite the main state
|
||
|
// as soon as a full message has completed
|
||
|
// but still keep the number of bytes written
|
||
|
if 0 == p.state.written {
|
||
|
p.written = 0
|
||
|
}
|
||
|
|
||
|
switch p.parseState {
|
||
|
case VersionState:
|
||
|
fmt.Println("version state", b[0])
|
||
|
p.state.version = b[0]
|
||
|
b = b[1:]
|
||
|
p.state.written += 1
|
||
|
p.parseState += 1
|
||
|
default:
|
||
|
// do nothing
|
||
|
}
|
||
|
|
||
|
switch p.state.version {
|
||
|
case V1:
|
||
|
fmt.Println("v1 unmarshal")
|
||
|
return p.written, p.unpackV1(b)
|
||
|
default:
|
||
|
return 0, errors.New("incorrect version or version not implemented")
|
||
|
}
|
||
|
}
|