frames.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. Payload []byte `oscar:"len_prefix=uint16"`
  23. }
  24. type SNACFrame struct {
  25. FoodGroup uint16
  26. SubGroup uint16
  27. Flags uint16
  28. RequestID uint32
  29. }
  30. type FLAPSignonFrame struct {
  31. FLAPVersion uint32
  32. TLVRestBlock
  33. }
  34. type SNACMessage struct {
  35. Frame SNACFrame
  36. Body any
  37. }
  38. // NewFlapClient creates a new FLAP client instance. startSeq is the initial
  39. // sequence value, which is typically 0. r receives FLAP messages, w writes
  40. // FLAP messages.
  41. func NewFlapClient(startSeq uint32, r io.Reader, w io.Writer) *FlapClient {
  42. return &FlapClient{
  43. sequence: startSeq,
  44. r: r,
  45. w: w,
  46. }
  47. }
  48. // FlapClient sends and receive FLAP frames to and from the server. It ensures
  49. // that the message sequence numbers are properly incremented after sending
  50. // each successive message. It is not safe to use with multiple goroutines
  51. // without synchronization.
  52. type FlapClient struct {
  53. sequence uint32
  54. r io.Reader
  55. w io.Writer
  56. }
  57. // SendSignonFrame sends a signon FLAP frame containing a list of TLVs to
  58. // authenticate or initiate a session.
  59. func (f *FlapClient) SendSignonFrame(tlvs []TLV) error {
  60. signonFrame := FLAPSignonFrame{
  61. FLAPVersion: 1,
  62. }
  63. if len(tlvs) > 0 {
  64. signonFrame.AppendList(tlvs)
  65. }
  66. buf := &bytes.Buffer{}
  67. if err := MarshalBE(signonFrame, buf); err != nil {
  68. return err
  69. }
  70. flap := FLAPFrame{
  71. StartMarker: 42,
  72. FrameType: FLAPFrameSignon,
  73. Sequence: uint16(f.sequence),
  74. Payload: buf.Bytes(),
  75. }
  76. if err := MarshalBE(flap, f.w); err != nil {
  77. return err
  78. }
  79. f.sequence++
  80. return nil
  81. }
  82. // ReceiveSignonFrame receives a signon FLAP response message.
  83. func (f *FlapClient) ReceiveSignonFrame() (FLAPSignonFrame, error) {
  84. flap := FLAPFrame{}
  85. if err := UnmarshalBE(&flap, f.r); err != nil {
  86. return FLAPSignonFrame{}, err
  87. }
  88. signonFrame := FLAPSignonFrame{}
  89. if err := UnmarshalBE(&signonFrame, bytes.NewBuffer(flap.Payload)); err != nil {
  90. return FLAPSignonFrame{}, err
  91. }
  92. return signonFrame, nil
  93. }
  94. // ReceiveFLAP receives a FLAP frame and body. It only returns a body if the
  95. // FLAP frame is a data frame.
  96. func (f *FlapClient) ReceiveFLAP() (FLAPFrame, error) {
  97. flap := FLAPFrame{}
  98. err := UnmarshalBE(&flap, f.r)
  99. if err != nil {
  100. err = fmt.Errorf("unable to unmarshal FLAP frame: %w", err)
  101. }
  102. return flap, err
  103. }
  104. // SendSignoffFrame sends a sign-off FLAP frame with attached TLVs as the last
  105. // request sent in the FLAP auth flow. This is unrelated to the Disconnect()
  106. // method, which sends a sign-off frame to terminate a BOS connection.
  107. // todo: combine this method with Disconnect()
  108. func (f *FlapClient) SendSignoffFrame(tlvs TLVRestBlock) error {
  109. tlvBuf := &bytes.Buffer{}
  110. if err := MarshalBE(tlvs, tlvBuf); err != nil {
  111. return err
  112. }
  113. flap := FLAPFrame{
  114. StartMarker: 42,
  115. FrameType: FLAPFrameSignoff,
  116. Sequence: uint16(f.sequence),
  117. Payload: tlvBuf.Bytes(),
  118. }
  119. if err := MarshalBE(flap, f.w); err != nil {
  120. return err
  121. }
  122. f.sequence++
  123. return nil
  124. }
  125. // SendSNAC sends a SNAC message wrapped in a FLAP frame.
  126. func (f *FlapClient) SendSNAC(frame SNACFrame, body any) error {
  127. snacBuf := &bytes.Buffer{}
  128. if err := MarshalBE(frame, snacBuf); err != nil {
  129. return err
  130. }
  131. if err := MarshalBE(body, snacBuf); err != nil {
  132. return err
  133. }
  134. flap := FLAPFrame{
  135. StartMarker: 42,
  136. FrameType: FLAPFrameData,
  137. Sequence: uint16(f.sequence),
  138. Payload: snacBuf.Bytes(),
  139. }
  140. if err := MarshalBE(flap, f.w); err != nil {
  141. return err
  142. }
  143. f.sequence++
  144. return nil
  145. }
  146. // ReceiveSNAC receives a SNAC message wrapped in a FLAP frame.
  147. func (f *FlapClient) ReceiveSNAC(frame *SNACFrame, body any) error {
  148. flap := FLAPFrame{}
  149. if err := UnmarshalBE(&flap, f.r); err != nil {
  150. return err
  151. }
  152. buf := bytes.NewBuffer(flap.Payload)
  153. if err := UnmarshalBE(frame, buf); err != nil {
  154. return err
  155. }
  156. return UnmarshalBE(body, buf)
  157. }
  158. // Disconnect sends a signoff FLAP frame.
  159. func (f *FlapClient) Disconnect() error {
  160. // gracefully disconnect so that the client does not try to
  161. // reconnect when the connection closes.
  162. flap := FLAPFrame{
  163. StartMarker: 42,
  164. FrameType: FLAPFrameSignoff,
  165. Sequence: uint16(f.sequence),
  166. }
  167. return MarshalBE(flap, f.w)
  168. }