tcpTransport.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. const TcpClient = require("./TcpClient");
  2. const crc = require('crc');
  3. class TcpTransport {
  4. constructor(ipAddress, port) {
  5. this.tcpClient = new TcpClient();
  6. this.sendCounter = 0;
  7. this.ipAddress = ipAddress;
  8. this.port = port;
  9. }
  10. async connect() {
  11. await this.tcpClient.connect(this.ipAddress, this.port);
  12. }
  13. /**
  14. * Sends the given packet (bytes array) to the connected peer
  15. * Original reference: https://core.telegram.org/mtproto#tcp-transport
  16. * The packets are encoded as: total length, sequence number, packet and checksum (CRC32)
  17. * @param packet
  18. */
  19. send(packet) {
  20. if (this.tcpClient.connected) {
  21. throw Error("not connected");
  22. }
  23. let buffer = Buffer.alloc(4 + 4);
  24. buffer.writeInt32LE(packet.length + 12, 0);
  25. buffer.writeInt32LE(this.sendCounter, 4);
  26. buffer = Buffer.concat([buffer, packet]);
  27. let tempBuffer = Buffer.alloc(4);
  28. tempBuffer.writeUInt32LE(crc.crc32(buffer), 0);
  29. buffer = Buffer.concat([buffer, tempBuffer]);
  30. this.tcpClient.write(buffer);
  31. this.sendCounter++;
  32. }
  33. /**
  34. * Receives a TCP message (tuple(sequence number, body)) from the connected peer
  35. * @returns {{body: {Buffer}, seq: {Buffer}}}
  36. */
  37. receive() {
  38. /**First read everything we need**/
  39. let packetLengthBytes = this.tcpClient.read(4);
  40. let packetLength = Buffer.from(packetLengthBytes).readInt32LE(0);
  41. let seqBytes = this.tcpClient.read(4);
  42. let seq = Buffer.from(seqBytes).readInt32LE(0);
  43. let body = this.tcpClient.read(packetLength - 12);
  44. let checksum = Buffer.from(this.tcpClient.read(4)).readUInt32LE(0);
  45. /**Then perform the checks**/
  46. let rv = Buffer.concat([packetLengthBytes, seqBytes, body]);
  47. let validChecksum = crc.crc32(rv);
  48. if (checksum !== validChecksum) {
  49. throw Error("invalid checksum");
  50. }
  51. /** If we passed the tests, we can then return a valid TCP message**/
  52. return {seq, body}
  53. }
  54. close() {
  55. if (this.tcpClient.connected) {
  56. this.tcpClient.close();
  57. }
  58. }
  59. /**
  60. * Cancels (stops) trying to receive from the
  61. * remote peer and raises an {Error}
  62. */
  63. cancelReceive() {
  64. this.tcpClient.cancelRead();
  65. }
  66. /**
  67. * Gets the client read delay
  68. * @returns {number}
  69. */
  70. getClientDelay() {
  71. return this.tcpClient.delay;
  72. }
  73. }
  74. module.exports = TcpTransport;