2018-05-10 15:22:19 +03:00
|
|
|
import errno
|
|
|
|
import struct
|
|
|
|
from zlib import crc32
|
|
|
|
|
|
|
|
from .common import Connection
|
|
|
|
from ...errors import InvalidChecksumError
|
|
|
|
from ...extensions import TcpClient
|
|
|
|
|
|
|
|
|
|
|
|
class ConnectionTcpFull(Connection):
|
|
|
|
"""
|
|
|
|
Default Telegram mode. Sends 12 additional bytes and
|
|
|
|
needs to calculate the CRC value of the packet itself.
|
|
|
|
"""
|
2018-06-17 12:46:56 +03:00
|
|
|
def __init__(self, *, loop, timeout, proxy=None):
|
|
|
|
super().__init__(loop=loop, timeout=timeout, proxy=proxy)
|
2018-05-10 15:22:19 +03:00
|
|
|
self._send_counter = 0
|
2018-06-14 20:35:12 +03:00
|
|
|
self.conn = TcpClient(
|
2018-06-17 12:46:56 +03:00
|
|
|
timeout=self._timeout, loop=self._loop, proxy=self._proxy
|
2018-06-14 20:35:12 +03:00
|
|
|
)
|
2018-05-10 15:22:19 +03:00
|
|
|
self.read = self.conn.read
|
|
|
|
self.write = self.conn.write
|
|
|
|
|
2018-06-06 21:41:01 +03:00
|
|
|
async def connect(self, ip, port):
|
2018-05-10 15:22:19 +03:00
|
|
|
try:
|
2018-06-06 22:42:48 +03:00
|
|
|
await self.conn.connect(ip, port)
|
2018-05-10 15:22:19 +03:00
|
|
|
except OSError as e:
|
|
|
|
if e.errno == errno.EISCONN:
|
|
|
|
return # Already connected, no need to re-set everything up
|
|
|
|
else:
|
|
|
|
raise
|
|
|
|
|
|
|
|
self._send_counter = 0
|
|
|
|
|
|
|
|
def get_timeout(self):
|
|
|
|
return self.conn.timeout
|
|
|
|
|
|
|
|
def is_connected(self):
|
2018-06-06 22:42:48 +03:00
|
|
|
return self.conn.is_connected
|
2018-05-10 15:22:19 +03:00
|
|
|
|
2018-06-06 21:41:01 +03:00
|
|
|
async def close(self):
|
2018-05-10 15:22:19 +03:00
|
|
|
self.conn.close()
|
|
|
|
|
2018-06-06 21:41:01 +03:00
|
|
|
async def recv(self):
|
2018-06-06 22:42:48 +03:00
|
|
|
packet_len_seq = await self.read(8) # 4 and 4
|
2018-05-10 15:22:19 +03:00
|
|
|
packet_len, seq = struct.unpack('<ii', packet_len_seq)
|
2018-06-06 22:42:48 +03:00
|
|
|
body = await self.read(packet_len - 8)
|
|
|
|
checksum = struct.unpack('<I', body[-4:])[0]
|
|
|
|
body = body[:-4]
|
2018-05-10 15:22:19 +03:00
|
|
|
|
|
|
|
valid_checksum = crc32(packet_len_seq + body)
|
|
|
|
if checksum != valid_checksum:
|
|
|
|
raise InvalidChecksumError(checksum, valid_checksum)
|
|
|
|
|
|
|
|
return body
|
|
|
|
|
2018-06-06 21:41:01 +03:00
|
|
|
async def send(self, message):
|
2018-05-10 15:22:19 +03:00
|
|
|
# https://core.telegram.org/mtproto#tcp-transport
|
|
|
|
# total length, sequence number, packet and checksum (CRC32)
|
|
|
|
length = len(message) + 12
|
|
|
|
data = struct.pack('<ii', length, self._send_counter) + message
|
|
|
|
crc = struct.pack('<I', crc32(data))
|
|
|
|
self._send_counter += 1
|
2018-06-06 22:42:48 +03:00
|
|
|
await self.write(data + crc)
|