frames.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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. // ReqIDFromServer is the SNAC frame Request ID value that indicates the SNAC
  40. // is initiated by the server. Some clients, such as the Java AIM 1.1.19,
  41. // completely fail to process some server SNACs if the high bit is not set on
  42. // request ID.
  43. const ReqIDFromServer = 1 << 31
  44. type FLAPSignonFrame struct {
  45. FLAPVersion uint32
  46. TLVRestBlock
  47. }
  48. type SNACMessage struct {
  49. Frame SNACFrame
  50. Body any
  51. }
  52. // NewFlapClient creates a new FLAP client instance. startSeq is the initial
  53. // sequence value, which is typically 0. r receives FLAP messages, w writes
  54. // FLAP messages.
  55. func NewFlapClient(startSeq uint32, r io.Reader, w io.Writer) *FlapClient {
  56. return &FlapClient{
  57. sequence: startSeq,
  58. r: r,
  59. w: w,
  60. }
  61. }
  62. // FlapClient sends and receive FLAP frames to and from the server. It ensures
  63. // that the message sequence numbers are properly incremented after sending
  64. // each successive message. It is not safe to use with multiple goroutines
  65. // without synchronization.
  66. type FlapClient struct {
  67. sequence uint32
  68. r io.Reader
  69. w io.Writer
  70. }
  71. // Fixes a race condition caused by testify. Yup...
  72. // https://github.com/stretchr/testify/issues/625
  73. func (f *FlapClient) String() string {
  74. return ""
  75. }
  76. // SendSignonFrame sends a signon FLAP frame containing a list of TLVs to
  77. // authenticate or initiate a session.
  78. func (f *FlapClient) SendSignonFrame(tlvs []TLV) error {
  79. signonFrame := FLAPSignonFrame{
  80. FLAPVersion: 1,
  81. }
  82. if len(tlvs) > 0 {
  83. signonFrame.AppendList(tlvs)
  84. }
  85. buf := &bytes.Buffer{}
  86. if err := MarshalBE(signonFrame, buf); err != nil {
  87. return err
  88. }
  89. flap := FLAPFrame{
  90. StartMarker: 42,
  91. FrameType: FLAPFrameSignon,
  92. Sequence: uint16(f.sequence),
  93. Payload: buf.Bytes(),
  94. }
  95. if err := MarshalBE(flap, f.w); err != nil {
  96. return err
  97. }
  98. f.sequence++
  99. return nil
  100. }
  101. // ReceiveSignonFrame receives a signon FLAP response message.
  102. func (f *FlapClient) ReceiveSignonFrame() (FLAPSignonFrame, error) {
  103. flap := FLAPFrame{}
  104. if err := UnmarshalBE(&flap, f.r); err != nil {
  105. return FLAPSignonFrame{}, err
  106. }
  107. signonFrame := FLAPSignonFrame{}
  108. if err := UnmarshalBE(&signonFrame, bytes.NewBuffer(flap.Payload)); err != nil {
  109. return FLAPSignonFrame{}, err
  110. }
  111. return signonFrame, nil
  112. }
  113. // ReceiveFLAP receives a FLAP frame and body. It only returns a body if the
  114. // FLAP frame is a data frame.
  115. func (f *FlapClient) ReceiveFLAP() (FLAPFrame, error) {
  116. flap := FLAPFrame{}
  117. err := UnmarshalBE(&flap, f.r)
  118. if err != nil {
  119. err = fmt.Errorf("unable to unmarshal FLAP frame: %w", err)
  120. }
  121. return flap, err
  122. }
  123. // SendSignoffFrame sends a sign-off FLAP frame with attached TLVs as the last
  124. // request sent in the FLAP auth flow. This is unrelated to the Disconnect()
  125. // method, which sends a sign-off frame to terminate a BOS connection.
  126. // todo: combine this method with Disconnect()
  127. func (f *FlapClient) SendSignoffFrame(tlvs TLVRestBlock) error {
  128. tlvBuf := &bytes.Buffer{}
  129. if err := MarshalBE(tlvs, tlvBuf); err != nil {
  130. return err
  131. }
  132. flap := FLAPFrame{
  133. StartMarker: 42,
  134. FrameType: FLAPFrameSignoff,
  135. Sequence: uint16(f.sequence),
  136. Payload: tlvBuf.Bytes(),
  137. }
  138. if err := MarshalBE(flap, f.w); err != nil {
  139. return err
  140. }
  141. f.sequence++
  142. return nil
  143. }
  144. // SendSNAC sends a SNAC message wrapped in a FLAP frame.
  145. func (f *FlapClient) SendSNAC(frame SNACFrame, body any) error {
  146. snacBuf := &bytes.Buffer{}
  147. if err := MarshalBE(frame, snacBuf); err != nil {
  148. return err
  149. }
  150. if err := MarshalBE(body, snacBuf); err != nil {
  151. return err
  152. }
  153. flap := FLAPFrame{
  154. StartMarker: 42,
  155. FrameType: FLAPFrameData,
  156. Sequence: uint16(f.sequence),
  157. Payload: snacBuf.Bytes(),
  158. }
  159. if err := MarshalBE(flap, f.w); err != nil {
  160. return err
  161. }
  162. f.sequence++
  163. return nil
  164. }
  165. func (f *FlapClient) SendDataFrame(payload []byte) error {
  166. flap := FLAPFrame{
  167. StartMarker: 42,
  168. FrameType: FLAPFrameData,
  169. Sequence: uint16(f.sequence),
  170. Payload: payload,
  171. }
  172. if err := MarshalBE(flap, f.w); err != nil {
  173. return err
  174. }
  175. f.sequence++
  176. return nil
  177. }
  178. func (f *FlapClient) SendKeepAliveFrame() error {
  179. flap := FLAPFrame{
  180. StartMarker: 42,
  181. FrameType: FLAPFrameKeepAlive,
  182. Sequence: uint16(f.sequence),
  183. }
  184. if err := MarshalBE(flap, f.w); err != nil {
  185. return err
  186. }
  187. f.sequence++
  188. return nil
  189. }
  190. // ReceiveSNAC receives a SNAC message wrapped in a FLAP frame.
  191. func (f *FlapClient) ReceiveSNAC(frame *SNACFrame, body any) error {
  192. flap := FLAPFrame{}
  193. if err := UnmarshalBE(&flap, f.r); err != nil {
  194. return err
  195. }
  196. buf := bytes.NewBuffer(flap.Payload)
  197. if err := UnmarshalBE(frame, buf); err != nil {
  198. return err
  199. }
  200. return UnmarshalBE(body, buf)
  201. }
  202. // Disconnect sends a signoff FLAP frame.
  203. func (f *FlapClient) Disconnect() error {
  204. flap := FLAPFrameDisconnect{
  205. StartMarker: 42,
  206. FrameType: FLAPFrameSignoff,
  207. Sequence: uint16(f.sequence),
  208. }
  209. return MarshalBE(flap, f.w)
  210. }