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

Net Core exception in websock receive (works in .Net Framework 4.6.2) when sending large data #27190

Closed
DigitalNut opened this issue Aug 21, 2018 · 5 comments
Labels
area-System.Net bug tenet-compatibility Incompatibility with previous versions or .NET Framework
Milestone

Comments

@DigitalNut
Copy link

Exception in websock receive in .NET Core 2.1. Works in .NET Framework 4.6.2 (same code). This happens when receiving large binary data. I tested receiving binary data that is approx. 50K and 100K. In all cases the websocket receive throws the exception.
Visual Studio 15.8.0

My log from my process shows exception:
Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.

Attached is my log from process.
Net2.1ExceptionWebsocket.txt

I'm not sure if this is the same issue reported on StackOverflow
https://stackoverflow.com/questions/47233356/dotnet-core-2-websocket-receiveasync-throws-exception-with-small-buffer

This is my outer thread loop looks like this:

        private void ThreadNetworkLoop(object npObject)
        {
            byte[] buffer = new byte[8192];
            bool loop = true;

            NetProtocol npSource = ((State)npObject).npSource;
            NetProtocol npDestination = ((State)npObject).npDestination;
            Console.WriteLine("Starting Thread " + Thread.CurrentThread.ManagedThreadId);

            try
            {
                int bytesRead = 0;
                while (loop)
                {
                    bytesRead = npSource.Receive(buffer, 0, buffer.Length, Timeout.Infinite, false);
                    Console.WriteLine("Thread:" + Thread.CurrentThread.ManagedThreadId + "  Received " + bytesRead);
                    if (bytesRead > 0)
                    {
                        npDestination.Send(buffer, bytesRead);
                    }
                    else
                    {
                        Console.WriteLine("Thread:" + Thread.CurrentThread.ManagedThreadId + "  0 bytes received -- closing");
                        npSource.Close();
                        npDestination.Close();
                        loop = false;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception :" + e.Message);
                npSource.Close();
                npDestination.Close();
            }
        }

The above npSource.Receive calls the following routine (below)

My Websock receive code looks like this:

        public int Receive(WebSocket ws, byte[] buffer, int offset, int expectedSize, int timeout = Timeout.Infinite, bool waitForExpectedSize = true)
        {
            bool stop = false;
            int count = 0;

            if (expectedSize == 0)
                return 0;


            try
            {
                while (!stop && (count < expectedSize))
                {
                    TraceLog.WriteLineThr($" offset: {offset}, count: {count}, expected size: {expectedSize}");

                    // we keep moving the segment over (offset) until we read everything
                    ArraySegment<byte> tempBuffer = new ArraySegment<byte>(buffer, offset, expectedSize - count);

                    // might have to do this in a loop until we received a End Of Message flag
                    Task<WebSocketReceiveResult> receiveResult = ws.ReceiveAsync(tempBuffer, CancellationToken.None);
                    receiveResult.Wait(timeout);

                    // do something, end of the message. Note: Not really needed as we know how many bytes to read
                    //if (receiveResult.Result.EndOfMessage)
                    //    break;

                    if (receiveResult.IsFaulted || receiveResult.IsCanceled)
                    {
                        TraceLog.WriteLineThr("WebSocket canceled/faulted received.");
                        return 0;
                    }
                    else if (receiveResult.Result.MessageType == WebSocketMessageType.Close)
                    {
                        TraceLog.WriteLineThr("Websocket close received.");
                        return 0;
                    }
                    else if (receiveResult.Result.Count <= 0)
                    {
                        TraceLog.WriteLineThr("received 0 bytes (Should we close?)");
                        return 0;
                    }
                    else if ((receiveResult.Result.Count > 0) && (receiveResult.Result.Count < expectedSize))
                    {
                        TraceLog.WriteLineThr("received less then expected. Read:" + receiveResult.Result.Count + " Expected:" + expectedSize + " waitForExpectedSize:" + waitForExpectedSize);
                        if (!waitForExpectedSize)
                            stop = true;
                    }
                    else if ((receiveResult.Result.Count > (expectedSize - count)))
                    {
                        // This one can't happen as we pass in a ArraySegment with the correct size
                        TraceLog.WriteLineThr("Error read more then expected, buffer overflow. Received:" + receiveResult.Result.Count);
                        return 0;
                    }
                    //Array.Copy(tempBuffer.Array, 0, buffer, count, receiveResult.Result.Count);
                    offset += receiveResult.Result.Count;
                    count += receiveResult.Result.Count;
                    receivedBytes += (ulong)receiveResult.Result.Count;
                    //TraceLog.WriteLineThr("Websocket: read: " + receiveResult.Result.Count + ", count: " + count + ", expected: " + expectedSize);
                }

                TraceLog.WriteLineThr("returning count: " + count);
                return count;
            }
            catch (AggregateException ae)
            {
                foreach (Exception ex in ae.InnerExceptions)
                    TraceLog.WriteLineThr(ex.Message);
                return 0;
            }
            catch (Exception e)
            {
                TraceLog.WriteLineThr(e.Message);
                return -1;
            }
        }
@DigitalNut DigitalNut changed the title Net Core exception in websock receive (works in .Net Framework 4.6.2) Net Core exception in websock receive (works in .Net Framework 4.6.2) when sending large data Aug 21, 2018
@karelz
Copy link
Member

karelz commented Aug 22, 2018

Do you have minimal repro we can try locally? (not just code snippets, but something that compiles)
Please try to remove all unnecessary code from it ...

@karelz
Copy link
Member

karelz commented Aug 22, 2018

Also I wonder if it works on .NET Core 2.0. Can you please give it a try?

@DigitalNut
Copy link
Author

Yes, this issue did occur on .NET Core 2.0. I waited to upgrade to .NET Core 2.1 to see if issue was fixed. I'll try to create sample code.

@DigitalNut
Copy link
Author

My mistake. It's working on .NET core 2.1 latest version that ships with Visual Studio 15.8.1. I had updated to 15.8.0 but forget to check if the update .NET Core 2.1 runtime fixed the problem. It working great with .NET Core 2.1 and the .NET framework. I tested with small & large binary data (1.4MB) and it worked great. Sorry for the inconvenience!

@karelz
Copy link
Member

karelz commented Aug 22, 2018

OK, if it works in latest 2.1, let's close it. Thanks!

@karelz karelz closed this as completed Aug 22, 2018
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 3.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net bug tenet-compatibility Incompatibility with previous versions or .NET Framework
Projects
None yet
Development

No branches or pull requests

3 participants