stun_conn.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package turn
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "net"
  6. "time"
  7. "github.com/pion/stun"
  8. "github.com/pion/turn/v2/internal/proto"
  9. )
  10. var (
  11. errInvalidTURNFrame = errors.New("data is not a valid TURN frame, no STUN or ChannelData found")
  12. errIncompleteTURNFrame = errors.New("data contains incomplete STUN or TURN frame")
  13. )
  14. // STUNConn wraps a net.Conn and implements
  15. // net.PacketConn by being STUN aware and
  16. // packetizing the stream
  17. type STUNConn struct {
  18. nextConn net.Conn
  19. buff []byte
  20. }
  21. const (
  22. stunHeaderSize = 20
  23. channelDataLengthSize = 2
  24. channelDataNumberSize = channelDataLengthSize
  25. channelDataHeaderSize = channelDataLengthSize + channelDataNumberSize
  26. channelDataPadding = 4
  27. )
  28. // Given a buffer give the last offset of the TURN frame
  29. // If the buffer isn't a valid STUN or ChannelData packet
  30. // or the length doesn't match return false
  31. func consumeSingleTURNFrame(p []byte) (int, error) {
  32. // Too short to determine if ChannelData or STUN
  33. if len(p) < 9 {
  34. return 0, errIncompleteTURNFrame
  35. }
  36. var datagramSize uint16
  37. switch {
  38. case stun.IsMessage(p):
  39. datagramSize = binary.BigEndian.Uint16(p[2:4]) + stunHeaderSize
  40. case proto.ChannelNumber(binary.BigEndian.Uint16(p[0:2])).Valid():
  41. datagramSize = binary.BigEndian.Uint16(p[channelDataNumberSize:channelDataHeaderSize])
  42. if paddingOverflow := (datagramSize + channelDataPadding) % channelDataPadding; paddingOverflow != 0 {
  43. datagramSize = (datagramSize + channelDataPadding) - paddingOverflow
  44. }
  45. datagramSize += channelDataHeaderSize
  46. case len(p) < stunHeaderSize:
  47. return 0, errIncompleteTURNFrame
  48. default:
  49. return 0, errInvalidTURNFrame
  50. }
  51. if len(p) < int(datagramSize) {
  52. return 0, errIncompleteTURNFrame
  53. }
  54. return int(datagramSize), nil
  55. }
  56. // ReadFrom implements ReadFrom from net.PacketConn
  57. func (s *STUNConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
  58. // First pass any buffered data from previous reads
  59. n, err = consumeSingleTURNFrame(s.buff)
  60. if errors.Is(err, errInvalidTURNFrame) {
  61. return 0, nil, err
  62. } else if err == nil {
  63. copy(p, s.buff[:n])
  64. s.buff = s.buff[n:]
  65. return n, s.nextConn.RemoteAddr(), nil
  66. }
  67. // Then read from the nextConn, appending to our buff
  68. n, err = s.nextConn.Read(p)
  69. if err != nil {
  70. return 0, nil, err
  71. }
  72. s.buff = append(s.buff, append([]byte{}, p[:n]...)...)
  73. return s.ReadFrom(p)
  74. }
  75. // WriteTo implements WriteTo from net.PacketConn
  76. func (s *STUNConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
  77. return s.nextConn.Write(p)
  78. }
  79. // Close implements Close from net.PacketConn
  80. func (s *STUNConn) Close() error {
  81. return s.nextConn.Close()
  82. }
  83. // LocalAddr implements LocalAddr from net.PacketConn
  84. func (s *STUNConn) LocalAddr() net.Addr {
  85. return s.nextConn.LocalAddr()
  86. }
  87. // SetDeadline implements SetDeadline from net.PacketConn
  88. func (s *STUNConn) SetDeadline(t time.Time) error {
  89. return s.nextConn.SetDeadline(t)
  90. }
  91. // SetReadDeadline implements SetReadDeadline from net.PacketConn
  92. func (s *STUNConn) SetReadDeadline(t time.Time) error {
  93. return s.nextConn.SetReadDeadline(t)
  94. }
  95. // SetWriteDeadline implements SetWriteDeadline from net.PacketConn
  96. func (s *STUNConn) SetWriteDeadline(t time.Time) error {
  97. return s.nextConn.SetWriteDeadline(t)
  98. }
  99. // NewSTUNConn creates a STUNConn
  100. func NewSTUNConn(nextConn net.Conn) *STUNConn {
  101. return &STUNConn{nextConn: nextConn}
  102. }