This repository was archived by the owner on Dec 5, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 370
Expand file tree
/
Copy pathTcpTransport.cs
More file actions
134 lines (113 loc) · 4.69 KB
/
Copy pathTcpTransport.cs
File metadata and controls
134 lines (113 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using TLSharp.Core.MTProto.Crypto;
namespace TLSharp.Core.Network
{
public delegate TcpClient TcpClientConnectionHandler(string address, int port);
public class TcpTransport : IDisposable
{
private TcpClient tcpClient;
private NetworkStream stream;
private int sendCounter = 0;
TcpClientConnectionHandler handler;
string address;
int port;
IPAddress ipAddress;
public TcpTransport(string address, int port, TcpClientConnectionHandler handler = null)
{
this.handler = handler;
this.address = address;
this.port = port;
ipAddress = IPAddress.Parse(address);
}
public async Task Connect()
{
if (handler == null)
{
if (tcpClient != null)
{
tcpClient.Close();
}
tcpClient = new TcpClient(ipAddress.AddressFamily);
sendCounter = 0;
try
{
await tcpClient.ConnectAsync(ipAddress, port);
} catch (Exception ex) {
throw new Exception ($"Problem when trying to connect to {ipAddress}:{port}; either there's no internet connection or the IP address version is not compatible (if the latter, consider using DataCenterIPVersion enum)",
ex);
}
}
else
tcpClient = handler(address, port);
if (tcpClient.Connected)
{
stream = tcpClient.GetStream();
}
}
public async Task Send(byte[] packet, CancellationToken token = default(CancellationToken))
{
if (!tcpClient.Connected)
throw new InvalidOperationException("Client not connected to server.");
var tcpMessage = new TcpMessage(sendCounter, packet);
await stream.WriteAsync(tcpMessage.Encode(), 0, tcpMessage.Encode().Length, token).ConfigureAwait(false);
sendCounter++;
}
public async Task<TcpMessage> Receive(CancellationToken token = default(CancellationToken))
{
var packetLengthBytes = new byte[4];
if (await stream.ReadAsync(packetLengthBytes, 0, 4, token).ConfigureAwait(false) != 4)
throw new InvalidOperationException("Couldn't read the packet length");
int packetLength = BitConverter.ToInt32(packetLengthBytes, 0);
var seqBytes = new byte[4];
if (await stream.ReadAsync(seqBytes, 0, 4, token).ConfigureAwait(false) != 4)
throw new InvalidOperationException("Couldn't read the sequence");
int seq = BitConverter.ToInt32(seqBytes, 0);
int readBytes = 0;
var body = new byte[packetLength - 12];
int neededToRead = packetLength - 12;
do
{
var bodyByte = new byte[packetLength - 12];
var availableBytes = await stream.ReadAsync(bodyByte, 0, neededToRead, token).ConfigureAwait(false);
neededToRead -= availableBytes;
Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes);
readBytes += availableBytes;
}
while (readBytes != packetLength - 12);
var crcBytes = new byte[4];
if (await stream.ReadAsync(crcBytes, 0, 4, token).ConfigureAwait(false) != 4)
throw new InvalidOperationException("Couldn't read the crc");
byte[] rv = new byte[packetLengthBytes.Length + seqBytes.Length + body.Length];
Buffer.BlockCopy(packetLengthBytes, 0, rv, 0, packetLengthBytes.Length);
Buffer.BlockCopy(seqBytes, 0, rv, packetLengthBytes.Length, seqBytes.Length);
Buffer.BlockCopy(body, 0, rv, packetLengthBytes.Length + seqBytes.Length, body.Length);
var crc32 = new Crc32();
var computedChecksum = crc32.ComputeHash(rv).Reverse();
if (!crcBytes.SequenceEqual(computedChecksum))
{
throw new InvalidOperationException("invalid checksum! skip");
}
return new TcpMessage(seq, body);
}
public bool IsConnected
{
get
{
return this.tcpClient != null && this.tcpClient.Connected;
}
}
public void Dispose()
{
if (tcpClient.Connected)
{
stream.Close();
tcpClient.Close();
}
}
}
}