nats.net icon indicating copy to clipboard operation
nats.net copied to clipboard

StreamReader in sendConnect eats half-completed INFO message packets

Open Madgvox opened this issue 5 months ago • 5 comments

Observed behavior

When I use the NATS client library in a C# console application, it works as expected. When I use it within the Unity game engine, it fails to connect and is stuck in a RECONNECTING state.

This bug requires some context: I am implementing the NATS C# library within the Unity game engine. For some reason, when the connection is upgraded to TLS, the PONG network message and subsequent INFO is truncated to 512 bytes. I have no idea why this happens (and it's not important for this bug report, but it reveals a bug within the library itself).

Here's a mock-up of what I see coming down the wire:

PONG
INFO {<big block of JSON conn

And then after a moment, I get the rest:

ection info>}

I traced the error to the message parser, which was choking on the truncated last portion of the INFO message. I then traced it back to the sendConnect method. Essentially, here's what's happening:

The sendConnect method reads from the stream for the PONG message. However, to accomplish this, it's creating a StreamReader and calling ReadLine() from it. This returns the PONG line, but the StreamReader also consumes the first portion of the INFO message (as seen above). This leaves the rest of the INFO message to be parsed inside the runLoop, which is not in the correct state to parse the message and dies. This repeats ad infinitum as addition PONG/INFO message pairs are sent.

When I replaced these two lines:

sr = new StreamReader(br, Encoding.UTF8, false, MaxControlLineSize, true);
result = sr.ReadLine();

with a hacked together solution that reads the PONG message byte-by-byte:

byte[] buf = new byte[4096];
byte next;
int i = 0;
do {
    next = (byte)br.ReadByte();
    if( next == '\n' || next == 0 ) {
        break;
    }
    buf[i] = next;
    i += 1;
} while( true );
result = Encoding.UTF8.GetString( buf, 0, i );
result = result.Trim();

then the library connected successfully and began operating normally.

In summary, the current logic eats any subsequent messages that follow the PONG message in the same packet. Under normal operating conditions this doesn't appear to have any ill-effects, but under the bizarre 512 limit imposed by the Unity game engine it results in a critical parsing error.

Expected behavior

When I use the NATS client library in the Unity game engine, it works as expected.

Server and client version

N/A to the server/client version Affects NATS C# 1.1.2

Host environment

This is the C# NATS library being run within the Unity Game Engine environment, on version 2021.3.29.

Steps to reproduce

I haven't determined whether this reliably reproduces the problem because I don't know the RC on Unity's side. But here's the essence of my setup:

  1. Download Unity Game Engine 2021.3.29
  2. Set up a NATS server with TLS required
  3. Import the C# NATS library
  4. Set up a connection to the NATS server. Default options are fine. This was essentially the code I used to test:
using NATS.Client;
using UnityEngine;

public class NetworkTest : MonoBehaviour {
        private IConnection connection;

        public void Start () {
            var opts = ConnectionFactory.GetDefaultOptions();
            opts.Url = "the_url";
            opts.SetUserCredentials( "the_creds_path" );
            connection = new ConnectionFactory().CreateConnection( opts );
       }
}
  1. Run Unity in Play Mode. Assuming this isn't a fluke with my installation and is instead some weird quirk with that Unity version's TLS libraries, the connection should never successfully complete and will be stuck in a RECONNECTING state.

Madgvox avatar Jan 31 '24 06:01 Madgvox