message.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. package coap
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "reflect"
  8. "sort"
  9. "strconv"
  10. "strings"
  11. )
  12. // COAPType 代表消息类型
  13. type COAPType uint8
  14. // MaxTokenSize 最大token size
  15. const MaxTokenSize = 8
  16. const (
  17. // CON 需要被确认的请求
  18. CON COAPType = 0
  19. // NON 不需要被确认的请求
  20. NON COAPType = 1
  21. // ACK 应答消息,接受到CON消息的响应
  22. ACK COAPType = 2
  23. // RST 复位消息,当接收者接受到的消息包含一个错误,接受者解析消息或者不再关心发送者发送的内容,那么复位消息将会被发送
  24. RST COAPType = 3
  25. )
  26. // COAPCode 请求方法的类型
  27. type COAPCode uint8
  28. // request codes
  29. const (
  30. GET COAPCode = iota + 1
  31. POST
  32. PUT
  33. DELETE
  34. )
  35. // Response codes
  36. const (
  37. Empty COAPCode = 0
  38. Created COAPCode = 65
  39. Deleted COAPCode = 66
  40. Valid COAPCode = 67
  41. Changed COAPCode = 68
  42. Content COAPCode = 69
  43. Continue COAPCode = 95
  44. BadRequest COAPCode = 128
  45. Unauthorized COAPCode = 129
  46. BadOption COAPCode = 130
  47. Forbidden COAPCode = 131
  48. NotFound COAPCode = 132
  49. MethodNotAllowed COAPCode = 133
  50. NotAcceptable COAPCode = 134
  51. RequestEntityIncomplete COAPCode = 136
  52. PreconditionFailed COAPCode = 140
  53. RequestEntityTooLarge COAPCode = 141
  54. UnsupportedMediaType COAPCode = 143
  55. InternalServerError COAPCode = 160
  56. NotImplemented COAPCode = 161
  57. BadGateway COAPCode = 162
  58. ServiceUnavailable COAPCode = 163
  59. GatewayTimeout COAPCode = 164
  60. ProxyingNotSupported COAPCode = 165
  61. )
  62. // MediaType 请求消息的媒体类型 对应Content-Format
  63. type MediaType uint16
  64. // Content formats.
  65. const (
  66. TextPlain MediaType = 0 // text/plain;charset=utf-8
  67. AppXML MediaType = 41 // application/xml
  68. AppOctets MediaType = 42 // application/octet-stream
  69. AppExi MediaType = 47 // application/exi
  70. AppJSON MediaType = 50 // application/json
  71. AppCBOR MediaType = 60 //application/cbor (RFC 7049)
  72. )
  73. func (c MediaType) String() string {
  74. switch c {
  75. case TextPlain:
  76. return "text/plain;charset=utf-8"
  77. case AppXML:
  78. return "application/xml"
  79. case AppOctets:
  80. return "application/octet-stream"
  81. case AppExi:
  82. return "application/exi"
  83. case AppJSON:
  84. return "application/json"
  85. case AppCBOR:
  86. return "application/cbor (RFC 7049)"
  87. }
  88. return "Unknown media type: 0x" + strconv.FormatInt(int64(c), 16)
  89. }
  90. // OptionID Option编号
  91. type OptionID uint8
  92. // Option IDs.
  93. const (
  94. IfMatch OptionID = 1
  95. URIHost OptionID = 3
  96. ETag OptionID = 4
  97. IfNoneMatch OptionID = 5
  98. Observe OptionID = 6
  99. URIPort OptionID = 7
  100. LocationPath OptionID = 8
  101. URIPath OptionID = 11
  102. ContentFormat OptionID = 12
  103. MaxAge OptionID = 14
  104. URIQuery OptionID = 15
  105. Accept OptionID = 17
  106. LocationQuery OptionID = 20
  107. Block2 OptionID = 23
  108. Block1 OptionID = 27
  109. Size2 OptionID = 28
  110. ProxyURI OptionID = 35
  111. ProxyScheme OptionID = 39
  112. Size1 OptionID = 60
  113. )
  114. // Option value format (RFC7252 section 3.2)
  115. type valueFormat uint8
  116. const (
  117. valueUnknown valueFormat = iota
  118. valueEmpty
  119. valueOpaque
  120. valueUint
  121. valueString
  122. )
  123. type optionDef struct {
  124. valueFormat valueFormat
  125. minLen int
  126. maxLen int
  127. }
  128. var coapOptionDefs = map[OptionID]optionDef{
  129. IfMatch: optionDef{valueFormat: valueOpaque, minLen: 0, maxLen: 8},
  130. URIHost: optionDef{valueFormat: valueString, minLen: 1, maxLen: 255},
  131. ETag: optionDef{valueFormat: valueOpaque, minLen: 1, maxLen: 8},
  132. IfNoneMatch: optionDef{valueFormat: valueEmpty, minLen: 0, maxLen: 0},
  133. Observe: optionDef{valueFormat: valueUint, minLen: 0, maxLen: 3},
  134. URIPort: optionDef{valueFormat: valueUint, minLen: 0, maxLen: 2},
  135. LocationPath: optionDef{valueFormat: valueString, minLen: 0, maxLen: 255},
  136. URIPath: optionDef{valueFormat: valueString, minLen: 0, maxLen: 255},
  137. ContentFormat: optionDef{valueFormat: valueUint, minLen: 0, maxLen: 2},
  138. MaxAge: optionDef{valueFormat: valueUint, minLen: 0, maxLen: 4},
  139. URIQuery: optionDef{valueFormat: valueString, minLen: 0, maxLen: 255},
  140. Accept: optionDef{valueFormat: valueUint, minLen: 0, maxLen: 2},
  141. LocationQuery: optionDef{valueFormat: valueString, minLen: 0, maxLen: 255},
  142. Block2: optionDef{valueFormat: valueUint, minLen: 0, maxLen: 3},
  143. Block1: optionDef{valueFormat: valueUint, minLen: 0, maxLen: 3},
  144. Size2: optionDef{valueFormat: valueUint, minLen: 0, maxLen: 4},
  145. ProxyURI: optionDef{valueFormat: valueString, minLen: 1, maxLen: 1034},
  146. ProxyScheme: optionDef{valueFormat: valueString, minLen: 1, maxLen: 255},
  147. Size1: optionDef{valueFormat: valueUint, minLen: 0, maxLen: 4},
  148. }
  149. type option struct {
  150. ID OptionID
  151. Value interface{}
  152. }
  153. func encodeInt(v uint32) []byte {
  154. switch {
  155. case v == 0:
  156. return nil
  157. case v < 256:
  158. return []byte{byte(v)}
  159. case v < 65536:
  160. rv := []byte{0, 0}
  161. binary.BigEndian.PutUint16(rv, uint16(v))
  162. return rv
  163. case v < 16777216:
  164. rv := []byte{0, 0, 0, 0}
  165. binary.BigEndian.PutUint32(rv, uint32(v))
  166. return rv[1:]
  167. default:
  168. rv := []byte{0, 0, 0, 0}
  169. binary.BigEndian.PutUint32(rv, uint32(v))
  170. return rv
  171. }
  172. }
  173. func decodeInt(b []byte) uint32 {
  174. tmp := []byte{0, 0, 0, 0}
  175. copy(tmp[4-len(b):], b)
  176. return binary.BigEndian.Uint32(tmp)
  177. }
  178. func (o option) toBytes() []byte {
  179. var v uint32
  180. switch i := o.Value.(type) {
  181. case string:
  182. return []byte(i)
  183. case []byte:
  184. return i
  185. case MediaType:
  186. v = uint32(i)
  187. case int:
  188. v = uint32(i)
  189. case int32:
  190. v = uint32(i)
  191. case uint:
  192. v = uint32(i)
  193. case uint32:
  194. v = i
  195. default:
  196. panic(fmt.Errorf("invalid type for option %x: %T (%v)",
  197. o.ID, o.Value, o.Value))
  198. }
  199. return encodeInt(v)
  200. }
  201. type options []option
  202. func (o options) Len() int {
  203. return len(o)
  204. }
  205. func (o options) Less(i, j int) bool {
  206. if o[i].ID == o[j].ID {
  207. return i < j
  208. }
  209. return o[i].ID < o[j].ID
  210. }
  211. func (o options) Swap(i, j int) {
  212. o[i], o[j] = o[j], o[i]
  213. }
  214. func (o options) Remove(oid OptionID) options {
  215. idx := 0
  216. for i := 0; i < len(o); i++ {
  217. if o[i].ID != oid {
  218. o[idx] = o[i]
  219. idx++
  220. }
  221. }
  222. return o[:idx]
  223. }
  224. const (
  225. extoptByteCode = 13
  226. extoptByteAddend = 13
  227. extoptWordCode = 14
  228. extoptWordAddend = 269
  229. extoptError = 15
  230. )
  231. // Message interface
  232. type Message interface {
  233. Encode() ([]byte, error)
  234. Decode(data []byte) error
  235. Option(opid OptionID) interface{}
  236. Path() []string
  237. PathString() string
  238. SetPath([]string)
  239. SetPathString(s string)
  240. AddOption(opid OptionID, val interface{})
  241. RemoveOption(opid OptionID)
  242. IsConfirmable() bool
  243. OptionStrings(opid OptionID) []string
  244. GetMessageID() uint16
  245. GetToken() []byte
  246. GetCode() COAPCode
  247. GetPayload() []byte
  248. }
  249. // BaseMessage COAP 消息体
  250. type BaseMessage struct {
  251. Type COAPType
  252. Code COAPCode
  253. MessageID uint16
  254. Token []byte
  255. Payload []byte
  256. Opts options
  257. }
  258. // GetToken get token
  259. func (m *BaseMessage) GetToken() []byte {
  260. return m.Token
  261. }
  262. // GetMessageID get message id
  263. func (m *BaseMessage) GetMessageID() uint16 {
  264. return m.MessageID
  265. }
  266. // GetCode get code
  267. func (m *BaseMessage) GetCode() COAPCode {
  268. return m.Code
  269. }
  270. // Encode 消息打包
  271. func (m *BaseMessage) Encode() ([]byte, error) {
  272. tmpbuf := []byte{0, 0}
  273. binary.BigEndian.PutUint16(tmpbuf, m.MessageID)
  274. buf := bytes.Buffer{}
  275. buf.Write([]byte{
  276. (1 << 6) | (uint8(m.Type) << 4) | uint8(0xf&len(m.Token)),
  277. byte(m.Code),
  278. tmpbuf[0], tmpbuf[1],
  279. })
  280. buf.Write(m.Token)
  281. extendOpt := func(opt int) (int, int) {
  282. ext := 0
  283. if opt >= extoptByteAddend {
  284. if opt >= extoptWordAddend {
  285. ext = opt - extoptWordAddend
  286. opt = extoptWordCode
  287. } else {
  288. ext = opt - extoptByteAddend
  289. opt = extoptByteCode
  290. }
  291. }
  292. return opt, ext
  293. }
  294. writeOptHeader := func(delta, length int) {
  295. d, dx := extendOpt(delta)
  296. l, lx := extendOpt(length)
  297. buf.WriteByte(byte(d<<4) | byte(l))
  298. tmp := []byte{0, 0}
  299. writeExt := func(opt, ext int) {
  300. switch opt {
  301. case extoptByteCode:
  302. buf.WriteByte(byte(ext))
  303. case extoptWordCode:
  304. binary.BigEndian.PutUint16(tmp, uint16(ext))
  305. buf.Write(tmp)
  306. }
  307. }
  308. writeExt(d, dx)
  309. writeExt(l, lx)
  310. }
  311. sort.Stable(&m.Opts)
  312. prev := 0
  313. for _, o := range m.Opts {
  314. b := o.toBytes()
  315. writeOptHeader(int(o.ID)-prev, len(b))
  316. buf.Write(b)
  317. prev = int(o.ID)
  318. }
  319. if len(m.Payload) > 0 {
  320. buf.Write([]byte{0xff})
  321. }
  322. buf.Write(m.Payload)
  323. return buf.Bytes(), nil
  324. }
  325. // Decode 消息解包
  326. func (m *BaseMessage) Decode(data []byte) error {
  327. if len(data) < 4 {
  328. return errors.New("short packet")
  329. }
  330. if data[0]>>6 != 1 {
  331. return errors.New("invalid version")
  332. }
  333. m.Type = COAPType((data[0] >> 4) & 0x3)
  334. tokenLen := int(data[0] & 0xf)
  335. if tokenLen > 8 {
  336. return ErrInvalidTokenLen
  337. }
  338. m.Code = COAPCode(data[1])
  339. m.MessageID = binary.BigEndian.Uint16(data[2:4])
  340. if tokenLen > 0 {
  341. m.Token = make([]byte, tokenLen)
  342. }
  343. if len(data) < 4+tokenLen {
  344. return errors.New("truncated")
  345. }
  346. copy(m.Token, data[4:4+tokenLen])
  347. b := data[4+tokenLen:]
  348. prev := 0
  349. parseExtOpt := func(opt int) (int, error) {
  350. switch opt {
  351. case extoptByteCode:
  352. if len(b) < 1 {
  353. return -1, errors.New("truncated")
  354. }
  355. opt = int(b[0]) + extoptByteAddend
  356. b = b[1:]
  357. case extoptWordCode:
  358. if len(b) < 2 {
  359. return -1, errors.New("truncated")
  360. }
  361. opt = int(binary.BigEndian.Uint16(b[:2])) + extoptWordAddend
  362. b = b[2:]
  363. }
  364. return opt, nil
  365. }
  366. for len(b) > 0 {
  367. if b[0] == 0xff {
  368. b = b[1:]
  369. break
  370. }
  371. delta := int(b[0] >> 4)
  372. length := int(b[0] & 0x0f)
  373. if delta == extoptError || length == extoptError {
  374. return errors.New("unexpected extended option marker")
  375. }
  376. b = b[1:]
  377. delta, err := parseExtOpt(delta)
  378. if err != nil {
  379. return err
  380. }
  381. length, err = parseExtOpt(length)
  382. if err != nil {
  383. return err
  384. }
  385. if len(b) < length {
  386. return errors.New("truncated")
  387. }
  388. oid := OptionID(prev + delta)
  389. opval := parseOptionValue(oid, b[:length])
  390. b = b[length:]
  391. prev = int(oid)
  392. if opval != nil {
  393. m.Opts = append(m.Opts, option{ID: oid, Value: opval})
  394. }
  395. }
  396. m.Payload = b
  397. return nil
  398. }
  399. // IsConfirmable 如果是CON类型的消息类型,返回true
  400. func (m *BaseMessage) IsConfirmable() bool {
  401. return m.Type == CON
  402. }
  403. // GetPayload get payload
  404. func (m *BaseMessage) GetPayload() []byte {
  405. return m.Payload
  406. }
  407. // Option get option by id
  408. func (m *BaseMessage) Option(o OptionID) interface{} {
  409. for _, v := range m.Opts {
  410. if o == v.ID {
  411. return v.Value
  412. }
  413. }
  414. return nil
  415. }
  416. // Options 获取所的option value
  417. func (m *BaseMessage) Options(o OptionID) []interface{} {
  418. var rv []interface{}
  419. for _, v := range m.Opts {
  420. if o == v.ID {
  421. rv = append(rv, v.Value)
  422. }
  423. }
  424. return rv
  425. }
  426. // OptionStrings get option strings by id
  427. func (m *BaseMessage) OptionStrings(o OptionID) []string {
  428. var rv []string
  429. for _, o := range m.Options(o) {
  430. rv = append(rv, o.(string))
  431. }
  432. return rv
  433. }
  434. // Path 获取URIPath
  435. func (m *BaseMessage) Path() []string {
  436. return m.OptionStrings(URIPath)
  437. }
  438. // PathString gets a path as a / separated string.
  439. func (m *BaseMessage) PathString() string {
  440. return strings.Join(m.Path(), "/")
  441. }
  442. // SetPathString sets a path by a / separated string.
  443. func (m *BaseMessage) SetPathString(s string) {
  444. switch s {
  445. case "", "/":
  446. //root path is not set as option
  447. return
  448. default:
  449. if s[0] == '/' {
  450. s = s[1:]
  451. }
  452. m.SetPath(strings.Split(s, "/"))
  453. }
  454. }
  455. //RemoveOption remove a given opid
  456. func (m *BaseMessage) RemoveOption(opID OptionID) {
  457. m.Opts = m.Opts.Remove(opID)
  458. }
  459. // AddOption ``
  460. func (m *BaseMessage) AddOption(opID OptionID, val interface{}) {
  461. iv := reflect.ValueOf(val)
  462. if (iv.Kind() == reflect.Slice || iv.Kind() == reflect.Array) &&
  463. iv.Type().Elem().Kind() == reflect.String {
  464. for i := 0; i < iv.Len(); i++ {
  465. m.Opts = append(m.Opts, option{opID, iv.Index(i).Interface()})
  466. }
  467. return
  468. }
  469. m.Opts = append(m.Opts, option{opID, val})
  470. }
  471. // SetPath ``
  472. func (m *BaseMessage) SetPath(s []string) {
  473. m.SetOption(URIPath, s)
  474. }
  475. // SetOption sets an option, discarding any previous value
  476. func (m *BaseMessage) SetOption(opID OptionID, val interface{}) {
  477. m.RemoveOption(opID)
  478. m.AddOption(opID, val)
  479. }
  480. func parseOptionValue(optionID OptionID, valueBuf []byte) interface{} {
  481. def := coapOptionDefs[optionID]
  482. if def.valueFormat == valueUnknown {
  483. // Skip unrecognized options (RFC7252 section 5.4.1)
  484. return nil
  485. }
  486. if len(valueBuf) < def.minLen || len(valueBuf) > def.maxLen {
  487. // Skip options with illegal value length (RFC7252 section 5.4.3)
  488. return nil
  489. }
  490. switch def.valueFormat {
  491. case valueUint:
  492. intValue := decodeInt(valueBuf)
  493. if optionID == ContentFormat || optionID == Accept {
  494. return MediaType(intValue)
  495. }
  496. return intValue
  497. case valueString:
  498. return string(valueBuf)
  499. case valueOpaque, valueEmpty:
  500. return valueBuf
  501. }
  502. // Skip unrecognized options (should never be reached)
  503. return nil
  504. }
  505. // ParseMessage parse []byte to message
  506. func ParseMessage(data []byte) (Message, error) {
  507. rv := &BaseMessage{}
  508. return rv, rv.Decode(data)
  509. }