refactor(agent/stream): rename payload.go to header.go and update protocol header format

- Rename payload.go to header.go for clarity
- Add HostLength and PortLength fields to avoid NUL-terminated string scanning
- Add padding bytes to make struct size match headerSize
- Remove unused StreamRequestPayload struct and WriteTo method
- Add runtime size validation in init()
- Update PROTOCOL.md documentation
This commit is contained in:
yusing
2026-01-07 21:08:04 +08:00
parent 039ae26696
commit c8f617108e
2 changed files with 32 additions and 39 deletions

View File

@@ -7,15 +7,18 @@ This package implements a small header-based handshake that allows an authentica
The on-wire header is a fixed-size binary blob: The on-wire header is a fixed-size binary blob:
- `Version` (8 bytes) - `Version` (8 bytes)
- `HostLength` (1 byte)
- `Host` (255 bytes, NUL padded) - `Host` (255 bytes, NUL padded)
- `PortLength` (1 byte)
- `Port` (5 bytes, NUL padded) - `Port` (5 bytes, NUL padded)
- `Checksum` (4 bytes, big-endian CRC32) - `Checksum` (4 bytes, big-endian CRC32)
- `Padding` (14 bytes)
Total: `headerSize = 8 + 255 + 5 + 4 = 272` bytes. Total: `headerSize = 8 + 1 + 255 + 1 + 5 + 4 + 14 = 288` bytes.
Checksum is `crc32.ChecksumIEEE(header[0:headerSize-4])`. Checksum is `crc32.ChecksumIEEE(header[0:headerSize-4])`.
See [`StreamRequestHeader`](payload.go:26). See [`StreamRequestHeader`](header.go:10).
## TCP behavior ## TCP behavior

View File

@@ -1,12 +1,11 @@
package stream package stream
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"hash/crc32" "hash/crc32"
"io" "reflect"
"unsafe" "unsafe"
) )
@@ -16,7 +15,7 @@ const (
portSize = 5 portSize = 5
checksumSize = 4 // crc32 checksum checksumSize = 4 // crc32 checksum
headerSize = versionSize + hostSize + portSize + checksumSize headerSize = 288
) )
var version = [versionSize]byte{'0', '.', '1', '.', '0', 0, 0, 0} var version = [versionSize]byte{'0', '.', '1', '.', '0', 0, 0, 0}
@@ -24,15 +23,23 @@ var version = [versionSize]byte{'0', '.', '1', '.', '0', 0, 0, 0}
var ErrInvalidHeader = errors.New("invalid header") var ErrInvalidHeader = errors.New("invalid header")
type StreamRequestHeader struct { type StreamRequestHeader struct {
Version [versionSize]byte Version [versionSize]byte
Host [hostSize]byte
Port [portSize]byte HostLength uint8
Host [hostSize]byte
PortLength uint8
Port [portSize]byte
Checksum [checksumSize]byte Checksum [checksumSize]byte
_ [14]byte // padding to make the header size match the size of the struct
} }
type StreamRequestPayload struct { func init() {
StreamRequestHeader if headerSize != reflect.TypeFor[StreamRequestHeader]().Size() {
Data []byte panic("headerSize does not match the size of StreamRequestHeader")
}
} }
func NewStreamRequestHeader(host, port string) (*StreamRequestHeader, error) { func NewStreamRequestHeader(host, port string) (*StreamRequestHeader, error) {
@@ -44,7 +51,9 @@ func NewStreamRequestHeader(host, port string) (*StreamRequestHeader, error) {
} }
header := &StreamRequestHeader{} header := &StreamRequestHeader{}
copy(header.Version[:], version[:]) copy(header.Version[:], version[:])
header.HostLength = uint8(len(host))
copy(header.Host[:], host) copy(header.Host[:], host)
header.PortLength = uint8(len(port))
copy(header.Port[:], port) copy(header.Port[:], port)
header.updateChecksum() header.updateChecksum()
return header, nil return header, nil
@@ -54,39 +63,20 @@ func ToHeader(buf [headerSize]byte) *StreamRequestHeader {
return (*StreamRequestHeader)(unsafe.Pointer(&buf[0])) return (*StreamRequestHeader)(unsafe.Pointer(&buf[0]))
} }
// WriteTo implements the io.WriterTo interface.
func (p *StreamRequestPayload) WriteTo(w io.Writer) (n int64, err error) {
n1, err := w.Write(p.StreamRequestHeader.Bytes())
if err != nil {
return
}
if len(p.Data) == 0 {
return int64(n1), nil
}
n2, err := w.Write(p.Data)
if err != nil {
return
}
return int64(n1) + int64(n2), nil
}
func (h *StreamRequestHeader) GetHostPort() (string, string) { func (h *StreamRequestHeader) GetHostPort() (string, string) {
hostEnd := bytes.IndexByte(h.Host[:], 0) return string(h.Host[:h.HostLength]), string(h.Port[:h.PortLength])
portEnd := bytes.IndexByte(h.Port[:], 0)
if hostEnd == -1 {
hostEnd = hostSize
}
if portEnd == -1 {
portEnd = portSize
}
return string(h.Host[:hostEnd]), string(h.Port[:portEnd])
} }
func (h *StreamRequestHeader) Validate() bool { func (h *StreamRequestHeader) Validate() bool {
if h.Version != version { if h.Version != version {
return false return false
} }
if h.HostLength > hostSize {
return false
}
if h.PortLength > portSize {
return false
}
return h.validateChecksum() return h.validateChecksum()
} }
@@ -101,9 +91,9 @@ func (h *StreamRequestHeader) validateChecksum() bool {
} }
func (h *StreamRequestHeader) BytesWithoutChecksum() []byte { func (h *StreamRequestHeader) BytesWithoutChecksum() []byte {
return unsafe.Slice((*byte)(unsafe.Pointer(h)), headerSize-checksumSize) return (*[headerSize - checksumSize]byte)(unsafe.Pointer(h))[:]
} }
func (h *StreamRequestHeader) Bytes() []byte { func (h *StreamRequestHeader) Bytes() []byte {
return unsafe.Slice((*byte)(unsafe.Pointer(h)), headerSize) return (*[headerSize]byte)(unsafe.Pointer(h))[:]
} }