frames.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package wire
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. )
  7. type SNACError struct {
  8. Code uint16
  9. TLVRestBlock
  10. }
  11. const (
  12. FLAPFrameSignon uint8 = 0x01
  13. FLAPFrameData uint8 = 0x02
  14. FLAPFrameError uint8 = 0x03
  15. FLAPFrameSignoff uint8 = 0x04
  16. FLAPFrameKeepAlive uint8 = 0x05
  17. )
  18. type FLAPFrame struct {
  19. StartMarker uint8
  20. FrameType uint8
  21. Sequence uint16
  22. PayloadLength uint16
  23. }
  24. func (f FLAPFrame) ReadBody(r io.Reader) (*bytes.Buffer, error) {
  25. b := make([]byte, f.PayloadLength)
  26. if f.PayloadLength > 0 {
  27. if _, err := io.ReadFull(r, b); err != nil {
  28. return nil, err
  29. }
  30. }
  31. return bytes.NewBuffer(b), nil
  32. }
  33. type SNACFrame struct {
  34. FoodGroup uint16
  35. SubGroup uint16
  36. Flags uint16
  37. RequestID uint32
  38. }
  39. type FLAPSignonFrame struct {
  40. FLAPVersion uint32
  41. TLVRestBlock
  42. }
  43. type SNACMessage struct {
  44. Frame SNACFrame
  45. Body any
  46. }
  47. // NewFlapClient creates a new FLAP client instance. startSeq is the initial
  48. // sequence value, which is typically 0. r receives FLAP messages, w writes
  49. // FLAP messages.
  50. func NewFlapClient(startSeq uint32, r io.Reader, w io.Writer) *FlapClient {
  51. return &FlapClient{
  52. sequence: startSeq,
  53. r: r,
  54. w: w,
  55. }
  56. }
  57. // FlapClient sends and receive FLAP frames to and from the server. It ensures
  58. // that the message sequence numbers are properly incremented after sending
  59. // each successive message. It is not safe to use with multiple goroutines
  60. // without synchronization.
  61. type FlapClient struct {
  62. sequence uint32
  63. r io.Reader
  64. w io.Writer
  65. }
  66. // SendSignonFrame sends a signon FLAP frame containing a list of TLVs to
  67. // authenticate or initiate a session.
  68. func (f *FlapClient) SendSignonFrame(tlvs []TLV) error {
  69. signonFrame := FLAPSignonFrame{
  70. FLAPVersion: 1,
  71. }
  72. if len(tlvs) > 0 {
  73. signonFrame.AppendList(tlvs)
  74. }
  75. buf := &bytes.Buffer{}
  76. if err := Marshal(signonFrame, buf); err != nil {
  77. return err
  78. }
  79. flap := FLAPFrame{
  80. StartMarker: 42,
  81. FrameType: FLAPFrameSignon,
  82. Sequence: uint16(f.sequence),
  83. PayloadLength: uint16(buf.Len()),
  84. }
  85. if err := Marshal(flap, f.w); err != nil {
  86. return err
  87. }
  88. if _, err := f.w.Write(buf.Bytes()); err != nil {
  89. return err
  90. }
  91. f.sequence++
  92. return nil
  93. }
  94. // ReceiveSignonFrame receives a signon FLAP response message.
  95. func (f *FlapClient) ReceiveSignonFrame() (FLAPSignonFrame, error) {
  96. flap := FLAPFrame{}
  97. if err := Unmarshal(&flap, f.r); err != nil {
  98. return FLAPSignonFrame{}, err
  99. }
  100. buf, err := flap.ReadBody(f.r)
  101. if err != nil {
  102. return FLAPSignonFrame{}, err
  103. }
  104. signonFrame := FLAPSignonFrame{}
  105. if err := Unmarshal(&signonFrame, buf); err != nil {
  106. return FLAPSignonFrame{}, err
  107. }
  108. return signonFrame, nil
  109. }
  110. // ReceiveFLAP receives a FLAP frame and body. It only returns a body if the
  111. // FLAP frame is a data frame.
  112. func (f *FlapClient) ReceiveFLAP() (FLAPFrame, *bytes.Buffer, error) {
  113. flap := FLAPFrame{}
  114. if err := Unmarshal(&flap, f.r); err != nil {
  115. return flap, nil, fmt.Errorf("unable to unmarshal FLAP frame: %w", err)
  116. }
  117. if flap.FrameType != FLAPFrameData {
  118. return flap, nil, nil
  119. }
  120. buf, err := flap.ReadBody(f.r)
  121. if err != nil {
  122. err = fmt.Errorf("unable to read FLAP body: %w", err)
  123. }
  124. return flap, buf, err
  125. }
  126. // SendSignoffFrame sends a sign-off FLAP frame with attached TLVs as the last
  127. // request sent in the FLAP auth flow. This is unrelated to the Disconnect()
  128. // method, which sends a sign-off frame to terminate a BOS connection.
  129. // todo: combine this method with Disconnect()
  130. func (f *FlapClient) SendSignoffFrame(tlvs TLVRestBlock) error {
  131. tlvBuf := &bytes.Buffer{}
  132. if err := Marshal(tlvs, tlvBuf); err != nil {
  133. return err
  134. }
  135. flap := FLAPFrame{
  136. StartMarker: 42,
  137. FrameType: FLAPFrameSignoff,
  138. Sequence: uint16(f.sequence),
  139. PayloadLength: uint16(tlvBuf.Len()),
  140. }
  141. if err := Marshal(flap, f.w); err != nil {
  142. return err
  143. }
  144. expectLen := tlvBuf.Len()
  145. c, err := f.w.Write(tlvBuf.Bytes())
  146. if err != nil {
  147. return err
  148. }
  149. if c != expectLen {
  150. panic("did not write the expected # of bytes")
  151. }
  152. f.sequence++
  153. return nil
  154. }
  155. // SendSNAC sends a SNAC message wrapped in a FLAP frame.
  156. func (f *FlapClient) SendSNAC(frame SNACFrame, body any) error {
  157. snacBuf := &bytes.Buffer{}
  158. if err := Marshal(frame, snacBuf); err != nil {
  159. return err
  160. }
  161. if err := Marshal(body, snacBuf); err != nil {
  162. return err
  163. }
  164. flap := FLAPFrame{
  165. StartMarker: 42,
  166. FrameType: FLAPFrameData,
  167. Sequence: uint16(f.sequence),
  168. PayloadLength: uint16(snacBuf.Len()),
  169. }
  170. if err := Marshal(flap, f.w); err != nil {
  171. return err
  172. }
  173. if _, err := f.w.Write(snacBuf.Bytes()); err != nil {
  174. return err
  175. }
  176. f.sequence++
  177. return nil
  178. }
  179. // ReceiveSNAC receives a SNAC message wrapped in a FLAP frame.
  180. func (f *FlapClient) ReceiveSNAC(frame *SNACFrame, body any) error {
  181. flap := FLAPFrame{}
  182. if err := Unmarshal(&flap, f.r); err != nil {
  183. return err
  184. }
  185. buf, err := flap.ReadBody(f.r)
  186. if err != nil {
  187. return err
  188. }
  189. if err := Unmarshal(frame, buf); err != nil {
  190. return err
  191. }
  192. return Unmarshal(body, buf)
  193. }
  194. // Disconnect sends a signoff FLAP frame.
  195. func (f *FlapClient) Disconnect() error {
  196. // gracefully disconnect so that the client does not try to
  197. // reconnect when the connection closes.
  198. flap := FLAPFrame{
  199. StartMarker: 42,
  200. FrameType: FLAPFrameSignoff,
  201. Sequence: uint16(f.sequence),
  202. PayloadLength: uint16(0),
  203. }
  204. return Marshal(flap, f.w)
  205. }