Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolved problem with StackOverflowException for .Net6.0 #703

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 191 additions & 0 deletions websocket-sharp/StreamThreader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using StreamThreads;
using static StreamThreads.StreamExtensions;

namespace WebSocketSharp
{
internal class StreamThreader
{
public WebSocket socket;
public Stream Stream;
public int buffersize = 1000000;

private MemoryStream _stream = new MemoryStream();
private StreamState state;
private byte[] buff;

public void Run()
{
buff = new byte[buffersize];
state = MainLoop().Await();

try
{
Stream.BeginRead(buff, 0, buffersize, StreamReader, null);
}
catch (ObjectDisposedException)
{
}
catch (Exception ex)
{
socket._logger.Fatal(ex.ToString());
socket.fatal("An exception has occurred while receiving.", ex);
}

}

private void StreamReader(IAsyncResult at)
{
try
{
int len = Stream.EndRead(at);
if (len == 0) return;

var oldpos = _stream.Position;
_stream.Position = _stream.Length;
_stream.WriteBytes(buff.SubArray(0, len), len);
_stream.Position = oldpos;

if (!Loop()) return;

if (_stream.Position != 0)
{
var oldstream = _stream;
_stream.CopyTo(_stream = new MemoryStream(), (int)(_stream.Length - _stream.Position));
oldstream.Dispose();
_stream.Position = 0;
}

Stream.BeginRead(buff, 0, buffersize, StreamReader, null);
}
catch (ObjectDisposedException)
{
}
catch (Exception ex)
{
socket._logger.Fatal(ex.ToString());
socket.fatal("An exception has occurred while receiving.", ex);
}
}

private bool Loop()
{
long curpos = _stream.Position;
while (true)
{
if (_stream.Position == _stream.Length)
break;

if (state.Loop()) return false;

if (curpos == _stream.Position)
break;

curpos = _stream.Position;
}

return true;
}

private IEnumerable<StreamState> MainLoop()
{
while (true)
{

yield return ReadStream(2).Await(out var header);

var frame = WebSocketFrame.processHeader(header);

yield return ReadExtendedPayloadLength(frame).Await();

yield return ReadMaskingKey(frame).Await();

yield return ReadPayloadData(frame).Await();

if (!socket.processReceivedFrame(frame))
continue;

if (!socket.HasMessage)
continue;

socket._inMessage = false;

if (socket._readyState != WebSocketState.Open)
break;

socket.message();
}

}

private IEnumerable<StreamState<byte[]>> ReadStream(int len)
{
yield return WaitFor<byte[]>(() => _stream.Length - _stream.Position >= len);

byte[] bytes = new byte[len];
_stream.Read(bytes, 0, len);

yield return Return(bytes);
}

private IEnumerable<StreamState> ReadExtendedPayloadLength(WebSocketFrame frame)
{
var len = frame.ExtendedPayloadLengthWidth;
if (len == 0)
{
frame._extPayloadLength = WebSocket.EmptyBytes;
yield break;
}

yield return ReadStream(len).Await(out var bytes);

if (bytes.Value.Length != len)
throw new WebSocketException("The extended payload length of a frame cannot be read from the stream.");

frame._extPayloadLength = bytes;
}

private IEnumerable<StreamState> ReadMaskingKey(WebSocketFrame frame)
{
var len = frame.IsMasked ? 4 : 0;
if (len == 0)
{
frame._maskingKey = WebSocket.EmptyBytes;
yield break;
}

yield return ReadStream(len).Await(out var bytes);

if (bytes.Value.Length != len)
throw new WebSocketException("The masking key of a frame cannot be read from the stream.");

frame._maskingKey = bytes;
}

private IEnumerable<StreamState> ReadPayloadData(WebSocketFrame frame)
{
var exactLen = frame.ExactPayloadLength;

if (exactLen > PayloadData.MaxLength)
throw new WebSocketException(CloseStatusCode.TooBig, "A frame has too long payload length.");

if (exactLen == 0)
{
frame._payloadData = PayloadData.Empty;
yield break;
}

yield return ReadStream((int)exactLen).Await(out var bytes);

if (bytes.Value.Length != (int)exactLen)
throw new WebSocketException("The payload data of a frame cannot be read from the stream.");

frame._payloadData = new PayloadData(bytes, (long)exactLen);
}


}
}
20 changes: 20 additions & 0 deletions websocket-sharp/StreamThreads/BackgroundState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;

namespace StreamThreads
{
internal class BackgroundState
{
internal bool Enabled = true;
internal bool SwitchState;
internal Action Lambda;
internal Predicate Condition;
internal StreamState BackgroundLoop;
internal IEnumerator<StreamState> SwitchFunction;
}

internal class BackgroundState<T> : BackgroundState
{
internal new IEnumerator<StreamState<T>> SwitchFunction;
}
}
61 changes: 61 additions & 0 deletions websocket-sharp/StreamThreads/IteratorReturnVariable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;

namespace StreamThreads
{
public enum IteratorStates { Inactive, Running, Ended, Terminated, Faulted }

public class IteratorReturnVariable
{
private object _value;
private bool _hasvalue = false;

public IteratorStates IteratorState = IteratorStates.Inactive;

public object Value
{
get
{
if (!_hasvalue)
throw new Exception("Variable value has not yet been set");

return _value;
}

set
{
_value = value;
_hasvalue = true;
}
}
public bool HasValue()
{
return _hasvalue;
}
public bool HasEnded => IteratorState == IteratorStates.Ended;
public bool WasTerminated => IteratorState == IteratorStates.Terminated;
public bool IsRunning => IteratorState == IteratorStates.Running;
public bool Faulted => IteratorState == IteratorStates.Faulted;
public override string ToString()
{
return $"{_value}";
}
public StreamState Await()
{
return new StreamStateLambda(() => !(IteratorState == IteratorStates.Inactive || IteratorState == IteratorStates.Running));
}
}

public class IteratorReturnVariable<T> : IteratorReturnVariable
{
public new T Value
{
get => (T)base.Value;
set => base.Value = value;
}

public static implicit operator T(IteratorReturnVariable<T> v)
{
return v.Value;
}
}
}
Loading