frames.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. // FLAPFrameDisconnect is the last FLAP frame sent to a client before
  25. // disconnection. It differs from FLAPFrame in that there is no payload length
  26. // prefix at the end, which causes Windows AIM clients to improperly handle
  27. // server disconnections, as when the regular FLAPFrame type is used.
  28. type FLAPFrameDisconnect struct {
  29. StartMarker uint8
  30. FrameType uint8
  31. Sequence uint16
  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. // Fixes a race condition caused by testify. Yup...
  67. // https://github.com/stretchr/testify/issues/625
  68. func (f *FlapClient) String() string {
  69. return ""
  70. }
  71. // SendSignonFrame sends a signon FLAP frame containing a list of TLVs to
  72. // authenticate or initiate a session.
  73. func (f *FlapClient) SendSignonFrame(tlvs []TLV) error {
  74. signonFrame := FLAPSignonFrame{
  75. FLAPVersion: 1,
  76. }
  77. if len(tlvs) > 0 {
  78. signonFrame.AppendList(tlvs)
  79. }
  80. buf := &bytes.Buffer{}
  81. if err := MarshalBE(signonFrame, buf); err != nil {
  82. return err
  83. }
  84. flap := FLAPFrame{
  85. StartMarker: 42,
  86. FrameType: FLAPFrameSignon,
  87. Sequence: uint16(f.sequence),
  88. Payload: buf.Bytes(),
  89. }
  90. if err := MarshalBE(flap, f.w); err != nil {
  91. return err
  92. }
  93. f.sequence++
  94. return nil
  95. }
  96. // ReceiveSignonFrame receives a signon FLAP response message.
  97. func (f *FlapClient) ReceiveSignonFrame() (FLAPSignonFrame, error) {
  98. flap := FLAPFrame{}
  99. if err := UnmarshalBE(&flap, f.r); err != nil {
  100. return FLAPSignonFrame{}, err
  101. }
  102. signonFrame := FLAPSignonFrame{}
  103. if err := UnmarshalBE(&signonFrame, bytes.NewBuffer(flap.Payload)); err != nil {
  104. return FLAPSignonFrame{}, err
  105. }
  106. return signonFrame, nil
  107. }
  108. // ReceiveFLAP receives a FLAP frame and body. It only returns a body if the
  109. // FLAP frame is a data frame.
  110. func (f *FlapClient) ReceiveFLAP() (FLAPFrame, error) {
  111. flap := FLAPFrame{}
  112. err := UnmarshalBE(&flap, f.r)
  113. if err != nil {
  114. err = fmt.Errorf("unable to unmarshal FLAP frame: %w", err)
  115. }
  116. return flap, err
  117. }
  118. // SendSignoffFrame sends a sign-off FLAP frame with attached TLVs as the last
  119. // request sent in the FLAP auth flow. This is unrelated to the Disconnect()
  120. // method, which sends a sign-off frame to terminate a BOS connection.
  121. // todo: combine this method with Disconnect()
  122. func (f *FlapClient) SendSignoffFrame(tlvs TLVRestBlock) error {
  123. tlvBuf := &bytes.Buffer{}
  124. if err := MarshalBE(tlvs, tlvBuf); err != nil {
  125. return err
  126. }
  127. flap := FLAPFrame{
  128. StartMarker: 42,
  129. FrameType: FLAPFrameSignoff,
  130. Sequence: uint16(f.sequence),
  131. Payload: tlvBuf.Bytes(),
  132. }
  133. if err := MarshalBE(flap, f.w); err != nil {
  134. return err
  135. }
  136. f.sequence++
  137. return nil
  138. }
  139. // SendSNAC sends a SNAC message wrapped in a FLAP frame.
  140. func (f *FlapClient) SendSNAC(frame SNACFrame, body any) error {
  141. snacBuf := &bytes.Buffer{}
  142. if err := MarshalBE(frame, snacBuf); err != nil {
  143. return err
  144. }
  145. if err := MarshalBE(body, snacBuf); err != nil {
  146. return err
  147. }
  148. flap := FLAPFrame{
  149. StartMarker: 42,
  150. FrameType: FLAPFrameData,
  151. Sequence: uint16(f.sequence),
  152. Payload: snacBuf.Bytes(),
  153. }
  154. if err := MarshalBE(flap, f.w); err != nil {
  155. return err
  156. }
  157. f.sequence++
  158. return nil
  159. }
  160. func (f *FlapClient) SendDataFrame(payload []byte) error {
  161. flap := FLAPFrame{
  162. StartMarker: 42,
  163. FrameType: FLAPFrameData,
  164. Sequence: uint16(f.sequence),
  165. Payload: payload,
  166. }
  167. if err := MarshalBE(flap, f.w); err != nil {
  168. return err
  169. }
  170. f.sequence++
  171. return nil
  172. }
  173. // ReceiveSNAC receives a SNAC message wrapped in a FLAP frame.
  174. func (f *FlapClient) ReceiveSNAC(frame *SNACFrame, body any) error {
  175. flap := FLAPFrame{}
  176. if err := UnmarshalBE(&flap, f.r); err != nil {
  177. return err
  178. }
  179. buf := bytes.NewBuffer(flap.Payload)
  180. if err := UnmarshalBE(frame, buf); err != nil {
  181. return err
  182. }
  183. return UnmarshalBE(body, buf)
  184. }
  185. // Disconnect sends a signoff FLAP frame.
  186. func (f *FlapClient) Disconnect() error {
  187. flap := FLAPFrameDisconnect{
  188. StartMarker: 42,
  189. FrameType: FLAPFrameSignoff,
  190. Sequence: uint16(f.sequence),
  191. }
  192. return MarshalBE(flap, f.w)
  193. }