writer.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package v2raywebsocket
  2. import (
  3. "encoding/binary"
  4. "io"
  5. "math/rand"
  6. "github.com/sagernet/sing/common/buf"
  7. "github.com/sagernet/sing/common/bufio"
  8. N "github.com/sagernet/sing/common/network"
  9. "github.com/sagernet/ws"
  10. )
  11. type Writer struct {
  12. writer N.ExtendedWriter
  13. isServer bool
  14. }
  15. func NewWriter(writer io.Writer, state ws.State) *Writer {
  16. return &Writer{
  17. bufio.NewExtendedWriter(writer),
  18. state == ws.StateServerSide,
  19. }
  20. }
  21. func (w *Writer) WriteBuffer(buffer *buf.Buffer) error {
  22. var payloadBitLength int
  23. dataLen := buffer.Len()
  24. data := buffer.Bytes()
  25. if dataLen < 126 {
  26. payloadBitLength = 1
  27. } else if dataLen < 65536 {
  28. payloadBitLength = 3
  29. } else {
  30. payloadBitLength = 9
  31. }
  32. var headerLen int
  33. headerLen += 1 // FIN / RSV / OPCODE
  34. headerLen += payloadBitLength
  35. if !w.isServer {
  36. headerLen += 4 // MASK KEY
  37. }
  38. header := buffer.ExtendHeader(headerLen)
  39. header[0] = byte(ws.OpBinary) | 0x80
  40. if w.isServer {
  41. header[1] = 0
  42. } else {
  43. header[1] = 1 << 7
  44. }
  45. if dataLen < 126 {
  46. header[1] |= byte(dataLen)
  47. } else if dataLen < 65536 {
  48. header[1] |= 126
  49. binary.BigEndian.PutUint16(header[2:], uint16(dataLen))
  50. } else {
  51. header[1] |= 127
  52. binary.BigEndian.PutUint64(header[2:], uint64(dataLen))
  53. }
  54. if !w.isServer {
  55. maskKey := rand.Uint32()
  56. binary.BigEndian.PutUint32(header[1+payloadBitLength:], maskKey)
  57. ws.Cipher(data, [4]byte(header[1+payloadBitLength:]), 0)
  58. }
  59. return wrapWsError(w.writer.WriteBuffer(buffer))
  60. }
  61. func (w *Writer) FrontHeadroom() int {
  62. return 14
  63. }