forked from RevenantX/LiteNetLib
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNetClient.cs
More file actions
302 lines (254 loc) · 9.53 KB
/
NetClient.cs
File metadata and controls
302 lines (254 loc) · 9.53 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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
using System;
using System.Text;
using LiteNetLib.Utils;
namespace LiteNetLib
{
public sealed class NetClient : NetBase
{
public int ReconnectDelay = 500;
public int MaxConnectAttempts = 10;
public bool PeerToPeerMode;
private NetPeer _peer;
private bool _connected;
private int _connectAttempts;
private int _connectTimer;
private ulong _connectId;
private readonly string _connectKey;
private readonly object _connectionCloseLock = new object();
public NetClient(INetEventListener listener, string connectKey) : base(listener)
{
_connectKey = connectKey;
}
public int Ping
{
get { return _peer == null ? 0 : _peer.Ping; }
}
/// <summary>
/// Returns client NetPeer
/// </summary>
/// <returns></returns>
public NetPeer Peer
{
get { return _peer; }
}
/// <summary>
/// Returns true if client connected
/// </summary>
public bool IsConnected
{
get { return _connected; }
}
private void CloseConnection(bool force, DisconnectReason reason, int socketErrorCode)
{
lock (_connectionCloseLock)
{
//Nothing to do
if (!IsRunning)
return;
//Send goodbye
if (_peer != null && !force && _connected)
{
//Send disconnect data
var disconnectPacket = NetPacket.CreateRawPacket(PacketProperty.Disconnect, 8);
FastBitConverter.GetBytes(disconnectPacket, 1, _connectId);
SendRaw(disconnectPacket, _peer.EndPoint);
}
//Close threads and socket close
base.Stop();
//Clear data
_peer = null;
_connected = false;
_connectTimer = 0;
_connectAttempts = 0;
SocketClearPeers();
//Send event to Listener
var netEvent = CreateEvent(NetEventType.Disconnect);
netEvent.DisconnectReason = reason;
netEvent.AdditionalData = socketErrorCode;
EnqueueEvent(netEvent);
}
}
/// <summary>
/// Force closes connection and stop all threads.
/// </summary>
public override void Stop()
{
CloseConnection(false, DisconnectReason.StopCalled, 0);
}
protected override void ProcessReceiveError(int socketErrorCode)
{
CloseConnection(true, DisconnectReason.SocketReceiveError, socketErrorCode);
base.ProcessReceiveError(socketErrorCode);
}
/// <summary>
/// Connect to NetServer or NetClient with PeerToPeerMode
/// </summary>
/// <param name="address">Server IP or hostname</param>
/// <param name="port">Server Port</param>
public void Connect(string address, int port)
{
//Create target endpoint
NetEndPoint ep = new NetEndPoint(address, port);
Connect(ep);
}
public void Connect(NetEndPoint target)
{
if (!IsRunning)
{
throw new Exception("Client is not running");
}
if (_peer != null)
{
//Already connected
return;
}
//Create connect id for proper connection
_connectId = (ulong)DateTime.UtcNow.Ticks;
NetUtils.DebugWrite(ConsoleColor.Cyan, "[CC] ConnectId: {0}", _connectId);
//Create reliable connection
_peer = CreatePeer(target);
_peer.DebugTextColor = ConsoleColor.Yellow;
//Create connection packet and send
SendConnectRequest();
_connectAttempts = 0;
}
private void SendConnectRequest()
{
//Get connect key bytes
byte[] keyData = Encoding.UTF8.GetBytes(_connectKey);
//Make initial packet
var connectPacket = NetPacket.CreateRawPacket(PacketProperty.ConnectRequest, 8+keyData.Length);
//Add data
FastBitConverter.GetBytes(connectPacket, 1, _connectId);
Buffer.BlockCopy(keyData, 0, connectPacket, 9, keyData.Length);
//Send raw
SendRaw(connectPacket, _peer.EndPoint);
}
protected override void PostProcessEvent(int deltaTime)
{
if (_peer == null)
return;
if (!_connected)
{
_connectTimer += deltaTime;
if (_connectTimer > ReconnectDelay)
{
_connectTimer = 0;
_connectAttempts++;
if (_connectAttempts > MaxConnectAttempts)
{
CloseConnection(true, DisconnectReason.ConnectionFailed, 0);
return;
}
//else send connect again
SendConnectRequest();
}
}
else if (_peer.TimeSinceLastPacket > DisconnectTimeout)
{
CloseConnection(true, DisconnectReason.Timeout, 0);
return;
}
_peer.Update(deltaTime);
}
internal override void ReceiveFromPeer(NetPacket packet, NetEndPoint remoteEndPoint)
{
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NC] Received message");
var netEvent = CreateEvent(NetEventType.Receive);
netEvent.DataReader.SetSource(packet.GetPacketData());
netEvent.Peer = _peer;
netEvent.RemoteEndPoint = remoteEndPoint;
EnqueueEvent(netEvent);
}
internal override void ProcessSendError(NetEndPoint remoteEndPoint, int socketErrorCode)
{
CloseConnection(true, DisconnectReason.SocketSendError, socketErrorCode);
base.ProcessSendError(remoteEndPoint, socketErrorCode);
}
private void ProcessConnectAccept()
{
if (_connected)
return;
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NC] Received connection accept");
_peer.StartConnectionTimer();
_connected = true;
var connectEvent = CreateEvent(NetEventType.Connect);
connectEvent.Peer = _peer;
EnqueueEvent(connectEvent);
}
protected override void ReceiveFromSocket(byte[] reusableBuffer, int count, NetEndPoint remoteEndPoint)
{
//Parse packet
//Peer null when P2P connection packets
NetPacket packet = _peer == null ? new NetPacket() : _peer.GetPacketFromPool(init: false);
if (!packet.FromBytes(reusableBuffer, count))
{
if(_peer != null)
_peer.Recycle(packet);
return;
}
//Check P2P mode
if (PeerToPeerMode && packet.Property == PacketProperty.ConnectRequest)
{
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NC] Received peer connect request");
string peerKey = Encoding.UTF8.GetString(packet.RawData, 9, packet.RawData.Length - 9);
if (peerKey != _connectKey)
{
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NC] Peer connect reject. Invalid key: " + peerKey);
return;
}
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NC] Peer connect accepting");
//Make initial packet and put id from received packet
var connectPacket = NetPacket.CreateRawPacket(PacketProperty.ConnectAccept, 8);
Buffer.BlockCopy(packet.RawData, 1, connectPacket, 1, 8);
//Check our peer and create
if (_peer == null)
{
//Create connect id for proper connection
Connect(remoteEndPoint);
}
//Send raw
SendRaw(connectPacket, remoteEndPoint);
//clean incoming packet
_peer.Recycle(packet);
//We connected
ProcessConnectAccept();
return;
}
//Check peer
if (_peer == null)
{
return;
}
//Check endpoint
if (!_peer.EndPoint.Equals(remoteEndPoint))
{
NetUtils.DebugWriteForce(ConsoleColor.DarkCyan, "[NC] Bad EndPoint " + remoteEndPoint);
return;
}
if (packet.Property == PacketProperty.Disconnect)
{
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NC] Received disconnection");
CloseConnection(true, DisconnectReason.RemoteConnectionClose, 0);
return;
}
if (packet.Property == PacketProperty.ConnectAccept)
{
if (_connected)
{
return;
}
//check connection id
if (BitConverter.ToUInt64(packet.RawData, 1) != _connectId)
{
return;
}
//connection things
ProcessConnectAccept();
return;
}
//Process income packet
_peer.ProcessPacket(packet);
}
}
}