Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

abridged.go 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package wrappers
  2. import (
  3. "bytes"
  4. "io"
  5. "net"
  6. "github.com/juju/errors"
  7. "github.com/9seconds/mtg/mtproto"
  8. "github.com/9seconds/mtg/wrappers"
  9. )
  10. type uint24 [3]byte
  11. const (
  12. abridgedSmallPacketLength = 0x7f
  13. abridgedQuickAckLength = 0x80
  14. abridgedLargePacketLength = 16777216 // 256 ^ 3
  15. )
  16. type AbridgedReadWriteCloserWithAddr struct {
  17. wrappers.BufferedReader
  18. conn wrappers.ReadWriteCloserWithAddr
  19. opts *mtproto.ConnectionOpts
  20. }
  21. func (a *AbridgedReadWriteCloserWithAddr) Read(p []byte) (int, error) {
  22. return a.BufferedRead(p, func() error {
  23. buf := &bytes.Buffer{}
  24. buf.Grow(3)
  25. q := make([]byte, 1)
  26. if _, err := io.CopyN(buf, a.conn, 1); err != nil {
  27. return errors.Annotate(err, "Cannot read message length")
  28. }
  29. msgLength := uint8(buf.Bytes()[0])
  30. q[0] = msgLength
  31. buf.Reset()
  32. if msgLength >= abridgedQuickAckLength {
  33. a.opts.ReadHacks.QuickAck = true
  34. msgLength -= abridgedQuickAckLength
  35. }
  36. msgLength32 := uint32(msgLength)
  37. if msgLength == abridgedSmallPacketLength {
  38. if _, err := io.CopyN(buf, a.conn, 3); err != nil {
  39. return errors.Annotate(err, "Cannot read the correct message length")
  40. }
  41. number := uint24{}
  42. copy(number[:], buf.Bytes())
  43. q = append(q, buf.Bytes()...)
  44. msgLength32 = fromUint24(number)
  45. }
  46. msgLength32 *= 4
  47. buf.Reset()
  48. buf.Grow(int(msgLength32))
  49. if _, err := io.CopyN(buf, a.conn, int64(msgLength32)); err != nil {
  50. return errors.Annotate(err, "Cannot read message")
  51. }
  52. q = append(q, buf.Bytes()...)
  53. a.Buffer.Write(buf.Bytes())
  54. return nil
  55. })
  56. }
  57. func (a *AbridgedReadWriteCloserWithAddr) Write(p []byte) (int, error) {
  58. if len(p)%4 != 0 {
  59. return 0, errors.Errorf("Incorrect packet length %d", len(p))
  60. }
  61. if a.opts.WriteHacks.SimpleAck {
  62. return a.conn.Write(reverseBytes(p))
  63. }
  64. packetLength := len(p) / 4
  65. switch {
  66. case packetLength < abridgedSmallPacketLength:
  67. newData := append([]byte{byte(packetLength)}, p...)
  68. return a.conn.Write(newData)
  69. case packetLength < abridgedLargePacketLength:
  70. length24 := toUint24(uint32(packetLength))
  71. buf := &bytes.Buffer{}
  72. buf.Grow(1 + 3 + len(p))
  73. buf.WriteByte(byte(abridgedSmallPacketLength))
  74. buf.Write(length24[:])
  75. buf.Write(p)
  76. return a.conn.Write(buf.Bytes())
  77. }
  78. return 0, errors.Errorf("Packet is too big %d", len(p))
  79. }
  80. func (a *AbridgedReadWriteCloserWithAddr) Close() error {
  81. return a.conn.Close()
  82. }
  83. func (a *AbridgedReadWriteCloserWithAddr) LocalAddr() *net.TCPAddr {
  84. return a.conn.LocalAddr()
  85. }
  86. func (a *AbridgedReadWriteCloserWithAddr) RemoteAddr() *net.TCPAddr {
  87. return a.conn.RemoteAddr()
  88. }
  89. func (a *AbridgedReadWriteCloserWithAddr) SocketID() string {
  90. return a.conn.SocketID()
  91. }
  92. func toUint24(number uint32) uint24 {
  93. return uint24{byte(number), byte(number >> 8), byte(number >> 16)}
  94. }
  95. func fromUint24(number uint24) uint32 {
  96. return uint32(number[0]) + (uint32(number[1]) << 8) + (uint32(number[2]) << 16)
  97. }
  98. func NewAbridgedRWC(conn wrappers.ReadWriteCloserWithAddr, connOpts *mtproto.ConnectionOpts) wrappers.ReadWriteCloserWithAddr {
  99. return &AbridgedReadWriteCloserWithAddr{
  100. BufferedReader: wrappers.NewBufferedReader(),
  101. conn: conn,
  102. opts: connOpts,
  103. }
  104. }