chunk_reconfig.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package sctp
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. // https://tools.ietf.org/html/rfc6525#section-3.1
  7. // chunkReconfig represents an SCTP Chunk used to reconfigure streams.
  8. //
  9. // 0 1 2 3
  10. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  11. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  12. // | Type = 130 | Chunk Flags | Chunk Length |
  13. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  14. // \ \
  15. // / Re-configuration Parameter /
  16. // \ \
  17. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  18. // \ \
  19. // / Re-configuration Parameter (optional) /
  20. // \ \
  21. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  22. type chunkReconfig struct {
  23. chunkHeader
  24. paramA param
  25. paramB param
  26. }
  27. var (
  28. errChunkParseParamTypeFailed = errors.New("failed to parse param type")
  29. errChunkMarshalParamAReconfigFailed = errors.New("unable to marshal parameter A for reconfig")
  30. errChunkMarshalParamBReconfigFailed = errors.New("unable to marshal parameter B for reconfig")
  31. )
  32. func (c *chunkReconfig) unmarshal(raw []byte) error {
  33. if err := c.chunkHeader.unmarshal(raw); err != nil {
  34. return err
  35. }
  36. pType, err := parseParamType(c.raw)
  37. if err != nil {
  38. return fmt.Errorf("%w: %v", errChunkParseParamTypeFailed, err)
  39. }
  40. a, err := buildParam(pType, c.raw)
  41. if err != nil {
  42. return err
  43. }
  44. c.paramA = a
  45. padding := getPadding(a.length())
  46. offset := a.length() + padding
  47. if len(c.raw) > offset {
  48. pType, err := parseParamType(c.raw[offset:])
  49. if err != nil {
  50. return fmt.Errorf("%w: %v", errChunkParseParamTypeFailed, err)
  51. }
  52. b, err := buildParam(pType, c.raw[offset:])
  53. if err != nil {
  54. return err
  55. }
  56. c.paramB = b
  57. }
  58. return nil
  59. }
  60. func (c *chunkReconfig) marshal() ([]byte, error) {
  61. out, err := c.paramA.marshal()
  62. if err != nil {
  63. return nil, fmt.Errorf("%w: %v", errChunkMarshalParamAReconfigFailed, err)
  64. }
  65. if c.paramB != nil {
  66. // Pad param A
  67. out = padByte(out, getPadding(len(out)))
  68. outB, err := c.paramB.marshal()
  69. if err != nil {
  70. return nil, fmt.Errorf("%w: %v", errChunkMarshalParamBReconfigFailed, err)
  71. }
  72. out = append(out, outB...)
  73. }
  74. c.typ = ctReconfig
  75. c.raw = out
  76. return c.chunkHeader.marshal()
  77. }
  78. func (c *chunkReconfig) check() (abort bool, err error) {
  79. // nolint:godox
  80. // TODO: check allowed combinations:
  81. // https://tools.ietf.org/html/rfc6525#section-3.1
  82. return true, nil
  83. }
  84. // String makes chunkReconfig printable
  85. func (c *chunkReconfig) String() string {
  86. res := fmt.Sprintf("Param A:\n %s", c.paramA)
  87. if c.paramB != nil {
  88. res += fmt.Sprintf("Param B:\n %s", c.paramB)
  89. }
  90. return res
  91. }