lcm.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Copyright 2018 Google, Inc. All rights reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style license
  4. // that can be found in the LICENSE file in the root of the source
  5. // tree.
  6. package layers
  7. import (
  8. "encoding/binary"
  9. "errors"
  10. "fmt"
  11. "github.com/google/gopacket"
  12. )
  13. const (
  14. // LCMShortHeaderMagic is the LCM small message header magic number
  15. LCMShortHeaderMagic uint32 = 0x4c433032
  16. // LCMFragmentedHeaderMagic is the LCM fragmented message header magic number
  17. LCMFragmentedHeaderMagic uint32 = 0x4c433033
  18. )
  19. // LCM (Lightweight Communications and Marshalling) is a set of libraries and
  20. // tools for message passing and data marshalling, targeted at real-time systems
  21. // where high-bandwidth and low latency are critical. It provides a
  22. // publish/subscribe message passing model and automatic
  23. // marshalling/unmarshalling code generation with bindings for applications in a
  24. // variety of programming languages.
  25. //
  26. // References
  27. // https://lcm-proj.github.io/
  28. // https://github.com/lcm-proj/lcm
  29. type LCM struct {
  30. // Common (short & fragmented header) fields
  31. Magic uint32
  32. SequenceNumber uint32
  33. // Fragmented header only fields
  34. PayloadSize uint32
  35. FragmentOffset uint32
  36. FragmentNumber uint16
  37. TotalFragments uint16
  38. // Common field
  39. ChannelName string
  40. // Gopacket helper fields
  41. Fragmented bool
  42. fingerprint LCMFingerprint
  43. contents []byte
  44. payload []byte
  45. }
  46. // LCMFingerprint is the type of a LCM fingerprint.
  47. type LCMFingerprint uint64
  48. var (
  49. // lcmLayerTypes contains a map of all LCM fingerprints that we support and
  50. // their LayerType
  51. lcmLayerTypes = map[LCMFingerprint]gopacket.LayerType{}
  52. layerTypeIndex = 1001
  53. )
  54. // RegisterLCMLayerType allows users to register decoders for the underlying
  55. // LCM payload. This is done based on the fingerprint that every LCM message
  56. // contains and which identifies it uniquely. If num is not the zero value it
  57. // will be used when registering with RegisterLayerType towards gopacket,
  58. // otherwise an incremental value starting from 1001 will be used.
  59. func RegisterLCMLayerType(num int, name string, fingerprint LCMFingerprint,
  60. decoder gopacket.Decoder) gopacket.LayerType {
  61. metadata := gopacket.LayerTypeMetadata{Name: name, Decoder: decoder}
  62. if num == 0 {
  63. num = layerTypeIndex
  64. layerTypeIndex++
  65. }
  66. lcmLayerTypes[fingerprint] = gopacket.RegisterLayerType(num, metadata)
  67. return lcmLayerTypes[fingerprint]
  68. }
  69. // SupportedLCMFingerprints returns a slice of all LCM fingerprints that has
  70. // been registered so far.
  71. func SupportedLCMFingerprints() []LCMFingerprint {
  72. fingerprints := make([]LCMFingerprint, 0, len(lcmLayerTypes))
  73. for fp := range lcmLayerTypes {
  74. fingerprints = append(fingerprints, fp)
  75. }
  76. return fingerprints
  77. }
  78. // GetLCMLayerType returns the underlying LCM message's LayerType.
  79. // This LayerType has to be registered by using RegisterLCMLayerType.
  80. func GetLCMLayerType(fingerprint LCMFingerprint) gopacket.LayerType {
  81. layerType, ok := lcmLayerTypes[fingerprint]
  82. if !ok {
  83. return gopacket.LayerTypePayload
  84. }
  85. return layerType
  86. }
  87. func decodeLCM(data []byte, p gopacket.PacketBuilder) error {
  88. lcm := &LCM{}
  89. err := lcm.DecodeFromBytes(data, p)
  90. if err != nil {
  91. return err
  92. }
  93. p.AddLayer(lcm)
  94. p.SetApplicationLayer(lcm)
  95. return p.NextDecoder(lcm.NextLayerType())
  96. }
  97. // DecodeFromBytes decodes the given bytes into this layer.
  98. func (lcm *LCM) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
  99. if len(data) < 8 {
  100. df.SetTruncated()
  101. return errors.New("LCM < 8 bytes")
  102. }
  103. offset := 0
  104. lcm.Magic = binary.BigEndian.Uint32(data[offset:4])
  105. offset += 4
  106. if lcm.Magic != LCMShortHeaderMagic && lcm.Magic != LCMFragmentedHeaderMagic {
  107. return fmt.Errorf("Received LCM header magic %v does not match know "+
  108. "LCM magic numbers. Dropping packet.", lcm.Magic)
  109. }
  110. lcm.SequenceNumber = binary.BigEndian.Uint32(data[offset:8])
  111. offset += 4
  112. if lcm.Magic == LCMFragmentedHeaderMagic {
  113. lcm.Fragmented = true
  114. lcm.PayloadSize = binary.BigEndian.Uint32(data[offset : offset+4])
  115. offset += 4
  116. lcm.FragmentOffset = binary.BigEndian.Uint32(data[offset : offset+4])
  117. offset += 4
  118. lcm.FragmentNumber = binary.BigEndian.Uint16(data[offset : offset+2])
  119. offset += 2
  120. lcm.TotalFragments = binary.BigEndian.Uint16(data[offset : offset+2])
  121. offset += 2
  122. } else {
  123. lcm.Fragmented = false
  124. }
  125. if !lcm.Fragmented || (lcm.Fragmented && lcm.FragmentNumber == 0) {
  126. buffer := make([]byte, 0)
  127. for _, b := range data[offset:] {
  128. offset++
  129. if b == 0 {
  130. break
  131. }
  132. buffer = append(buffer, b)
  133. }
  134. lcm.ChannelName = string(buffer)
  135. }
  136. lcm.fingerprint = LCMFingerprint(
  137. binary.BigEndian.Uint64(data[offset : offset+8]))
  138. lcm.contents = data[:offset]
  139. lcm.payload = data[offset:]
  140. return nil
  141. }
  142. // CanDecode returns a set of layers that LCM objects can decode.
  143. // As LCM objects can only decode the LCM layer, we just return that layer.
  144. func (lcm LCM) CanDecode() gopacket.LayerClass {
  145. return LayerTypeLCM
  146. }
  147. // NextLayerType specifies the LCM payload layer type following this header.
  148. // As LCM packets are serialized structs with uniq fingerprints for each uniq
  149. // combination of data types, lookup of correct layer type is based on that
  150. // fingerprint.
  151. func (lcm LCM) NextLayerType() gopacket.LayerType {
  152. if !lcm.Fragmented || (lcm.Fragmented && lcm.FragmentNumber == 0) {
  153. return GetLCMLayerType(lcm.fingerprint)
  154. }
  155. return gopacket.LayerTypeFragment
  156. }
  157. // LayerType returns LayerTypeLCM
  158. func (lcm LCM) LayerType() gopacket.LayerType {
  159. return LayerTypeLCM
  160. }
  161. // LayerContents returns the contents of the LCM header.
  162. func (lcm LCM) LayerContents() []byte {
  163. return lcm.contents
  164. }
  165. // LayerPayload returns the payload following this LCM header.
  166. func (lcm LCM) LayerPayload() []byte {
  167. return lcm.payload
  168. }
  169. // Payload returns the payload following this LCM header.
  170. func (lcm LCM) Payload() []byte {
  171. return lcm.LayerPayload()
  172. }
  173. // Fingerprint returns the LCM fingerprint of the underlying message.
  174. func (lcm LCM) Fingerprint() LCMFingerprint {
  175. return lcm.fingerprint
  176. }