2016-08-28 14:43:00 +03:00
|
|
|
# This file is based on TLSharp
|
|
|
|
# https://github.com/sochix/TLSharp/blob/master/TLSharp.Core/Network/TcpTransport.cs
|
2016-08-26 13:58:53 +03:00
|
|
|
from zlib import crc32
|
|
|
|
from network.tcp_message import TcpMessage
|
|
|
|
from network.tcp_client import TcpClient
|
|
|
|
|
|
|
|
|
|
|
|
class TcpTransport:
|
|
|
|
def __init__(self, ip_address, port):
|
|
|
|
self._tcp_client = TcpClient()
|
|
|
|
self._send_counter = 0
|
|
|
|
|
|
|
|
self._tcp_client.connect(ip_address, port)
|
|
|
|
|
|
|
|
def send(self, packet):
|
2016-08-28 14:43:00 +03:00
|
|
|
"""Sends the given packet (bytes array) to the connected peer"""
|
2016-08-26 13:58:53 +03:00
|
|
|
if not self._tcp_client.connected:
|
|
|
|
raise ConnectionError('Client not connected to server.')
|
|
|
|
|
2016-08-28 14:43:00 +03:00
|
|
|
# Get a TcpMessage which contains the given packet
|
2016-08-26 13:58:53 +03:00
|
|
|
tcp_message = TcpMessage(self._send_counter, packet)
|
|
|
|
|
2016-08-28 14:43:00 +03:00
|
|
|
# TODO In TLSharp, this is async; Should both send and receive be here too?
|
2016-08-26 13:58:53 +03:00
|
|
|
self._tcp_client.write(tcp_message.encode())
|
|
|
|
self._send_counter += 1
|
|
|
|
|
|
|
|
def receive(self):
|
2016-08-28 14:43:00 +03:00
|
|
|
"""Receives a TcpMessage from the connected peer"""
|
|
|
|
|
2016-08-26 13:58:53 +03:00
|
|
|
# First read everything
|
|
|
|
packet_length_bytes = self._tcp_client.read(4)
|
|
|
|
packet_length = int.from_bytes(packet_length_bytes, byteorder='big')
|
|
|
|
|
|
|
|
seq_bytes = self._tcp_client.read(4)
|
|
|
|
seq = int.from_bytes(seq_bytes, byteorder='big')
|
|
|
|
|
|
|
|
body = self._tcp_client.read(packet_length - 12)
|
|
|
|
|
|
|
|
checksum = int.from_bytes(self._tcp_client.read(4), byteorder='big')
|
|
|
|
|
|
|
|
# Then perform the checks
|
|
|
|
rv = packet_length_bytes + seq_bytes + body
|
|
|
|
valid_checksum = crc32(rv) & 0xFFFFFFFF # Ensure it's unsigned (http://stackoverflow.com/a/30092291/4759433)
|
|
|
|
|
|
|
|
if checksum != valid_checksum:
|
|
|
|
raise ValueError('Invalid checksum, skip')
|
|
|
|
|
2016-08-28 14:43:00 +03:00
|
|
|
# If we passed the tests, we can then return a valid TcpMessage
|
2016-08-26 13:58:53 +03:00
|
|
|
return TcpMessage(seq, body)
|
|
|
|
|
|
|
|
def dispose(self):
|
|
|
|
if self._tcp_client.connected:
|
|
|
|
self._tcp_client.close()
|