gtcp_conn_pkg.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gtcp
  7. import (
  8. "encoding/binary"
  9. "fmt"
  10. "time"
  11. )
  12. const (
  13. gPKG_HEADER_SIZE_DEFAULT = 2 // Header size for simple package protocol.
  14. gPKG_HEADER_SIZE_MAX = 4 // Max header size for simple package protocol.
  15. )
  16. // Package option for simple protocol.
  17. type PkgOption struct {
  18. // HeaderSize is used to mark the data length for next data receiving.
  19. // It's 2 bytes in default, 4 bytes max, which stands for the max data length
  20. // from 65535 to 4294967295 bytes.
  21. HeaderSize int
  22. // MaxDataSize is the data field size in bytes for data length validation.
  23. // If it's not manually set, it'll automatically be set correspondingly with the HeaderSize.
  24. MaxDataSize int
  25. // Retry policy when operation fails.
  26. Retry Retry
  27. }
  28. // SendPkg send data using simple package protocol.
  29. //
  30. // Simple package protocol: DataLength(24bit)|DataField(variant)。
  31. //
  32. // Note that,
  33. // 1. The DataLength is the length of DataField, which does not contain the header size.
  34. // 2. The integer bytes of the package are encoded using BigEndian order.
  35. func (c *Conn) SendPkg(data []byte, option ...PkgOption) error {
  36. pkgOption, err := getPkgOption(option...)
  37. if err != nil {
  38. return err
  39. }
  40. length := len(data)
  41. if length > pkgOption.MaxDataSize {
  42. return fmt.Errorf(
  43. `data too long, data size %d exceeds allowed max data size %d`,
  44. length, pkgOption.MaxDataSize,
  45. )
  46. }
  47. offset := gPKG_HEADER_SIZE_MAX - pkgOption.HeaderSize
  48. buffer := make([]byte, gPKG_HEADER_SIZE_MAX+len(data))
  49. binary.BigEndian.PutUint32(buffer[0:], uint32(length))
  50. copy(buffer[gPKG_HEADER_SIZE_MAX:], data)
  51. if pkgOption.Retry.Count > 0 {
  52. return c.Send(buffer[offset:], pkgOption.Retry)
  53. }
  54. return c.Send(buffer[offset:])
  55. }
  56. // SendPkgWithTimeout writes data to connection with timeout using simple package protocol.
  57. func (c *Conn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) (err error) {
  58. if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
  59. return err
  60. }
  61. defer c.SetSendDeadline(time.Time{})
  62. err = c.SendPkg(data, option...)
  63. return
  64. }
  65. // SendRecvPkg writes data to connection and blocks reading response using simple package protocol.
  66. func (c *Conn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error) {
  67. if err := c.SendPkg(data, option...); err == nil {
  68. return c.RecvPkg(option...)
  69. } else {
  70. return nil, err
  71. }
  72. }
  73. // SendRecvPkgWithTimeout writes data to connection and reads response with timeout using simple package protocol.
  74. func (c *Conn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error) {
  75. if err := c.SendPkg(data, option...); err == nil {
  76. return c.RecvPkgWithTimeout(timeout, option...)
  77. } else {
  78. return nil, err
  79. }
  80. }
  81. // RecvPkg receives data from connection using simple package protocol.
  82. func (c *Conn) RecvPkg(option ...PkgOption) (result []byte, err error) {
  83. var buffer []byte
  84. var length int
  85. pkgOption, err := getPkgOption(option...)
  86. if err != nil {
  87. return nil, err
  88. }
  89. // Header field.
  90. buffer, err = c.Recv(pkgOption.HeaderSize, pkgOption.Retry)
  91. if err != nil {
  92. return nil, err
  93. }
  94. switch pkgOption.HeaderSize {
  95. case 1:
  96. // It fills with zero if the header size is lesser than 4 bytes (uint32).
  97. length = int(binary.BigEndian.Uint32([]byte{0, 0, 0, buffer[0]}))
  98. case 2:
  99. length = int(binary.BigEndian.Uint32([]byte{0, 0, buffer[0], buffer[1]}))
  100. case 3:
  101. length = int(binary.BigEndian.Uint32([]byte{0, buffer[0], buffer[1], buffer[2]}))
  102. default:
  103. length = int(binary.BigEndian.Uint32([]byte{buffer[0], buffer[1], buffer[2], buffer[3]}))
  104. }
  105. // It here validates the size of the package.
  106. // It clears the buffer and returns error immediately if it validates failed.
  107. if length < 0 || length > pkgOption.MaxDataSize {
  108. return nil, fmt.Errorf(`invalid package size %d`, length)
  109. }
  110. // Empty package.
  111. if length == 0 {
  112. return nil, nil
  113. }
  114. // Data field.
  115. return c.Recv(length, pkgOption.Retry)
  116. }
  117. // RecvPkgWithTimeout reads data from connection with timeout using simple package protocol.
  118. func (c *Conn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) (data []byte, err error) {
  119. if err := c.SetRecvDeadline(time.Now().Add(timeout)); err != nil {
  120. return nil, err
  121. }
  122. defer c.SetRecvDeadline(time.Time{})
  123. data, err = c.RecvPkg(option...)
  124. return
  125. }
  126. // getPkgOption wraps and returns the PkgOption.
  127. // If no option given, it returns a new option with default value.
  128. func getPkgOption(option ...PkgOption) (*PkgOption, error) {
  129. pkgOption := PkgOption{}
  130. if len(option) > 0 {
  131. pkgOption = option[0]
  132. }
  133. if pkgOption.HeaderSize == 0 {
  134. pkgOption.HeaderSize = gPKG_HEADER_SIZE_DEFAULT
  135. }
  136. if pkgOption.HeaderSize > gPKG_HEADER_SIZE_MAX {
  137. return nil, fmt.Errorf(
  138. `package header size %d definition exceeds max header size %d`,
  139. pkgOption.HeaderSize, gPKG_HEADER_SIZE_MAX,
  140. )
  141. }
  142. if pkgOption.MaxDataSize == 0 {
  143. switch pkgOption.HeaderSize {
  144. case 1:
  145. pkgOption.MaxDataSize = 0xFF
  146. case 2:
  147. pkgOption.MaxDataSize = 0xFFFF
  148. case 3:
  149. pkgOption.MaxDataSize = 0xFFFFFF
  150. case 4:
  151. // math.MaxInt32 not math.MaxUint32
  152. pkgOption.MaxDataSize = 0x7FFFFFFF
  153. }
  154. }
  155. if pkgOption.MaxDataSize > 0x7FFFFFFF {
  156. return nil, fmt.Errorf(
  157. `package data size %d definition exceeds allowed max data size %d`,
  158. pkgOption.MaxDataSize, 0x7FFFFFFF,
  159. )
  160. }
  161. return &pkgOption, nil
  162. }