-
Notifications
You must be signed in to change notification settings - Fork 1
/
Receiver.cs
134 lines (116 loc) · 4.43 KB
/
Receiver.cs
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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Syndll2
{
internal class Receiver
{
private readonly byte[] _rawReceiveBuffer = new byte[SynelClient.PacketOverheadSize]; // intentionally small
private readonly List<byte> _receiveBuffer = new List<byte>(SynelClient.MaxPacketSize * 2);
private readonly Stream _stream;
private readonly Func<bool> _connected;
public Receiver(Stream stream, Func<bool> connected)
{
_stream = stream;
_connected = connected;
}
public Action<ReceivedMessage> MessageHandler { get; set; }
public void WatchStream()
{
// Make sure we can still read from the stream.
if (!_stream.CanRead)
return;
// Begin an async read operation on the stream.
try
{
_stream.BeginRead(_rawReceiveBuffer, 0, _rawReceiveBuffer.Length, OnDataReceived, null);
}
catch
{
// Swallow any exceptions. The stream is probably closed.
}
}
private void OnDataReceived(IAsyncResult asyncResult)
{
// Make sure we're still connected.
if (!_connected())
return;
// Make sure we can still read from the stream.
if (!_stream.CanRead)
return;
// Conclude the async read operation.
int bytesRead;
try
{
bytesRead = _stream.EndRead(asyncResult);
}
catch
{
// Swallow any exceptions. The stream is probably closed.
return;
}
// Make sure the data is still good.
// (We should never get back zeros at the start of the buffer, but it can happen during a forced disconnection.)
if (bytesRead > 0 && _rawReceiveBuffer[0] == 0)
return;
// Copy the raw data read into the full receive buffer.
_receiveBuffer.AddRange(_rawReceiveBuffer.Take(bytesRead));
// Read packets from the buffer, unless there's still more on the stream to read.
try
{
var networkStream = _stream as NetworkStream;
if (networkStream == null || !networkStream.DataAvailable)
ReadFromBuffer();
}
catch (ObjectDisposedException ex)
{
// this can happen due to dropped connection
Util.Log(ex.Message);
return;
}
// Sleep here to not eat up too much CPU
Thread.Sleep(10);
// Repeat, to continually watch the stream for incoming data.
WatchStream();
}
private void ReadFromBuffer()
{
// See if there is an EOT in the read buffer
int eotPosition;
while ((eotPosition = _receiveBuffer.IndexOf((byte)ControlChars.EOT)) >= 0)
{
// see if this is the last one in the current buffer
var lastInBuffer = eotPosition == _receiveBuffer.LastIndexOf((byte)ControlChars.EOT);
// Pull out all before and including the EOT
var size = eotPosition + 1;
var data = _receiveBuffer.Take(size).ToArray();
_receiveBuffer.RemoveRange(0, size);
// Get a string representation of the packet data
var packet = Encoding.ASCII.GetString(data);
// Try to parse it
var message = new ReceivedMessage { RawResponse = packet, LastInBuffer = lastInBuffer };
try
{
message.Response = Response.Parse(packet);
}
catch (InvalidCrcException)
{
// Don't fire when the message fails the CRC check
continue;
}
catch (Exception ex)
{
// pass any other exception into the event arguments
message.Exception = ex;
}
// Handle the message
if (MessageHandler != null && _connected())
MessageHandler(message);
}
}
}
}