frames.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package wire
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "sync"
  7. )
  8. type SNACError struct {
  9. Code uint16
  10. TLVRestBlock
  11. }
  12. const (
  13. FLAPFrameSignon uint8 = 0x01
  14. FLAPFrameData uint8 = 0x02
  15. FLAPFrameError uint8 = 0x03
  16. FLAPFrameSignoff uint8 = 0x04
  17. FLAPFrameKeepAlive uint8 = 0x05
  18. )
  19. type FLAPFrame struct {
  20. StartMarker uint8
  21. FrameType uint8
  22. Sequence uint16
  23. Payload []byte `oscar:"len_prefix=uint16"`
  24. }
  25. // FLAPFrameDisconnect is the last FLAP frame sent to a client before
  26. // disconnection. It differs from FLAPFrame in that there is no payload length
  27. // prefix at the end, which causes Windows AIM clients to improperly handle
  28. // server disconnections, as when the regular FLAPFrame type is used.
  29. type FLAPFrameDisconnect struct {
  30. StartMarker uint8
  31. FrameType uint8
  32. Sequence uint16
  33. }
  34. type SNACFrame struct {
  35. FoodGroup uint16
  36. SubGroup uint16
  37. Flags uint16
  38. RequestID uint32
  39. }
  40. // ReqIDFromServer is the SNAC frame Request ID value that indicates the SNAC
  41. // is initiated by the server. Some clients, such as the Java AIM 1.1.19,
  42. // completely fail to process some server SNACs if the high bit is not set on
  43. // request ID.
  44. const ReqIDFromServer = 1 << 31
  45. type FLAPSignonFrame struct {
  46. FLAPVersion uint32
  47. TLVRestBlock
  48. }
  49. type SNACMessage struct {
  50. Frame SNACFrame
  51. Body any
  52. }
  53. // NewFlapClient creates a new FLAP client instance. startSeq is the initial
  54. // sequence value, which is typically 0. r receives FLAP messages, w writes
  55. // FLAP messages.
  56. func NewFlapClient(startSeq uint32, r io.Reader, w io.Writer) *FlapClient {
  57. return &FlapClient{
  58. sequence: startSeq,
  59. r: r,
  60. w: w,
  61. mutex: sync.Mutex{},
  62. }
  63. }
  64. // FlapClient sends and receive FLAP frames to and from the server. It ensures
  65. // that the message sequence numbers are properly incremented after sending
  66. // each successive message. It is not safe to use with multiple goroutines
  67. // without synchronization.
  68. type FlapClient struct {
  69. sequence uint32
  70. r io.Reader
  71. w io.Writer
  72. mutex sync.Mutex
  73. }
  74. // Fixes a race condition caused by testify. Yup...
  75. // https://github.com/stretchr/testify/issues/625
  76. func (f *FlapClient) String() string {
  77. return ""
  78. }
  79. // SendSignonFrame sends a signon FLAP frame containing a list of TLVs to
  80. // authenticate or initiate a session.
  81. func (f *FlapClient) SendSignonFrame(tlvs []TLV) error {
  82. signonFrame := FLAPSignonFrame{
  83. FLAPVersion: 1,
  84. }
  85. if len(tlvs) > 0 {
  86. signonFrame.AppendList(tlvs)
  87. }
  88. buf := &bytes.Buffer{}
  89. if err := MarshalBE(signonFrame, buf); err != nil {
  90. return err
  91. }
  92. f.mutex.Lock()
  93. defer f.mutex.Unlock()
  94. flap := FLAPFrame{
  95. StartMarker: 42,
  96. FrameType: FLAPFrameSignon,
  97. Sequence: uint16(f.sequence),
  98. Payload: buf.Bytes(),
  99. }
  100. if err := MarshalBE(flap, f.w); err != nil {
  101. return err
  102. }
  103. f.sequence++
  104. return nil
  105. }
  106. // ReceiveSignonFrame receives a signon FLAP response message.
  107. func (f *FlapClient) ReceiveSignonFrame() (FLAPSignonFrame, error) {
  108. flap := FLAPFrame{}
  109. if err := UnmarshalBE(&flap, f.r); err != nil {
  110. return FLAPSignonFrame{}, err
  111. }
  112. signonFrame := FLAPSignonFrame{}
  113. if err := UnmarshalBE(&signonFrame, bytes.NewBuffer(flap.Payload)); err != nil {
  114. return FLAPSignonFrame{}, err
  115. }
  116. return signonFrame, nil
  117. }
  118. // ReceiveFLAP receives a FLAP frame and body. It only returns a body if the
  119. // FLAP frame is a data frame.
  120. func (f *FlapClient) ReceiveFLAP() (FLAPFrame, error) {
  121. flap := FLAPFrame{}
  122. err := UnmarshalBE(&flap, f.r)
  123. if err != nil {
  124. err = fmt.Errorf("unable to unmarshal FLAP frame: %w", err)
  125. }
  126. return flap, err
  127. }
  128. // SendSignoffFrame sends a sign-off FLAP frame with attached TLVs as the last
  129. // request sent in the FLAP auth flow. This is unrelated to the Disconnect()
  130. // method, which sends a sign-off frame to terminate a BOS connection.
  131. // todo: combine this method with Disconnect()
  132. func (f *FlapClient) SendSignoffFrame(tlvs TLVRestBlock) error {
  133. tlvBuf := &bytes.Buffer{}
  134. if err := MarshalBE(tlvs, tlvBuf); err != nil {
  135. return err
  136. }
  137. f.mutex.Lock()
  138. defer f.mutex.Unlock()
  139. flap := FLAPFrame{
  140. StartMarker: 42,
  141. FrameType: FLAPFrameSignoff,
  142. Sequence: uint16(f.sequence),
  143. Payload: tlvBuf.Bytes(),
  144. }
  145. if err := MarshalBE(flap, f.w); err != nil {
  146. return err
  147. }
  148. f.sequence++
  149. return nil
  150. }
  151. // SendSNAC sends a SNAC message wrapped in a FLAP frame.
  152. func (f *FlapClient) SendSNAC(frame SNACFrame, body any) error {
  153. snacBuf := &bytes.Buffer{}
  154. if err := MarshalBE(frame, snacBuf); err != nil {
  155. return err
  156. }
  157. if err := MarshalBE(body, snacBuf); err != nil {
  158. return err
  159. }
  160. f.mutex.Lock()
  161. defer f.mutex.Unlock()
  162. flap := FLAPFrame{
  163. StartMarker: 42,
  164. FrameType: FLAPFrameData,
  165. Sequence: uint16(f.sequence),
  166. Payload: snacBuf.Bytes(),
  167. }
  168. if err := MarshalBE(flap, f.w); err != nil {
  169. return err
  170. }
  171. f.sequence++
  172. return nil
  173. }
  174. func (f *FlapClient) SendDataFrame(payload []byte) error {
  175. f.mutex.Lock()
  176. defer f.mutex.Unlock()
  177. flap := FLAPFrame{
  178. StartMarker: 42,
  179. FrameType: FLAPFrameData,
  180. Sequence: uint16(f.sequence),
  181. Payload: payload,
  182. }
  183. if err := MarshalBE(flap, f.w); err != nil {
  184. return err
  185. }
  186. f.sequence++
  187. return nil
  188. }
  189. func (f *FlapClient) SendKeepAliveFrame() error {
  190. f.mutex.Lock()
  191. defer f.mutex.Unlock()
  192. flap := FLAPFrame{
  193. StartMarker: 42,
  194. FrameType: FLAPFrameKeepAlive,
  195. Sequence: uint16(f.sequence),
  196. }
  197. if err := MarshalBE(flap, f.w); err != nil {
  198. return err
  199. }
  200. f.sequence++
  201. return nil
  202. }
  203. // ReceiveSNAC receives a SNAC message wrapped in a FLAP frame.
  204. func (f *FlapClient) ReceiveSNAC(frame *SNACFrame, body any) error {
  205. flap := FLAPFrame{}
  206. if err := UnmarshalBE(&flap, f.r); err != nil {
  207. return err
  208. }
  209. buf := bytes.NewBuffer(flap.Payload)
  210. if err := UnmarshalBE(frame, buf); err != nil {
  211. return err
  212. }
  213. return UnmarshalBE(body, buf)
  214. }
  215. // Disconnect sends a signoff FLAP frame.
  216. func (f *FlapClient) Disconnect() error {
  217. f.mutex.Lock()
  218. defer f.mutex.Unlock()
  219. flap := FLAPFrameDisconnect{
  220. StartMarker: 42,
  221. FrameType: FLAPFrameSignoff,
  222. Sequence: uint16(f.sequence),
  223. }
  224. return MarshalBE(flap, f.w)
  225. }