package fabriccontrol import ( "encoding/binary" "errors" "fmt" "io" ) const ( frameMagic uint32 = 0x52415046 frameVersion uint8 = 1 frameHeaderSize = 32 maxPayload = 1024 * 1024 frameData uint8 = 5 trafficClassReliable uint8 = 4 controlForwardQUICStream uint64 = 3 ) type frame struct { Type uint8 TrafficClass uint8 StreamID uint64 Sequence uint64 Payload []byte } var errInvalidFrame = errors.New("invalid fabric frame") func readFrame(r io.Reader) (frame, error) { header := make([]byte, frameHeaderSize) if _, err := io.ReadFull(r, header); err != nil { return frame{}, err } if binary.BigEndian.Uint32(header[0:4]) != frameMagic || header[4] != frameVersion { return frame{}, errInvalidFrame } payloadLen := int(binary.BigEndian.Uint32(header[28:32])) if payloadLen > maxPayload { return frame{}, fmt.Errorf("%w: payload too large", errInvalidFrame) } out := frame{ Type: header[5], TrafficClass: header[8], StreamID: binary.BigEndian.Uint64(header[12:20]), Sequence: binary.BigEndian.Uint64(header[20:28]), } if payloadLen > 0 { out.Payload = make([]byte, payloadLen) if _, err := io.ReadFull(r, out.Payload); err != nil { return frame{}, err } } return out, nil } func writeFrame(w io.Writer, f frame) error { if len(f.Payload) > maxPayload { return fmt.Errorf("%w: payload too large", errInvalidFrame) } header := make([]byte, frameHeaderSize) binary.BigEndian.PutUint32(header[0:4], frameMagic) header[4] = frameVersion header[5] = f.Type header[8] = f.TrafficClass binary.BigEndian.PutUint64(header[12:20], f.StreamID) binary.BigEndian.PutUint64(header[20:28], f.Sequence) binary.BigEndian.PutUint32(header[28:32], uint32(len(f.Payload))) if _, err := w.Write(header); err != nil { return err } if len(f.Payload) == 0 { return nil } _, err := w.Write(f.Payload) return err }