Azure / amqpnetlite

AMQP 1.0 .NET Library
Apache License 2.0
396 stars 141 forks source link

Protocol violation when sending FLOW #575

Closed ansd closed 6 months ago

ansd commented 8 months ago

AMQP 1.0 section 2.7.4 states for FLOW field next-incoming-id:

This value MUST be set if the peer has received the begin frame for the session, and MUST NOT be set if it has not.

However, this client always sets field next-incoming-id irrespective whether it has received the server's BEGIN frame.

Reproduction steps:

In root folder of https://github.com/ansd/rabbitmq-server/tree/native-amqp-dotnet-bug, run

make -C deps/rabbitmq_amqp1_0 ct-system t=dotnet:redelivery

The test case fails with error

Amqp.AmqpException: next-incoming-id from FLOW (0) leads next-outgoing-id (4294967292)

Here is an easier example: Start latest RabbitMQ server https://github.com/rabbitmq/rabbitmq-server/tree/v3.12.8 (probably any other server will do it as well):

make run-broker PLUGINS="rabbitmq_amqp1_0 rabbitmq_management"

Create a C# project:

dotnet new console

Modify the .csproj file to contain

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <RootNamespace>rabbit_dot_net</RootNamespace>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="AmqpNetLite" Version="2.4.7" />
    </ItemGroup>
</Project>

and the Program.cs file to contain

using Amqp;

Trace.TraceLevel = TraceLevel.Frame;
Trace.TraceListener = (l, f, a) => Console.WriteLine(DateTime.Now.ToString("[hh:mm:ss.fff]") + " " + string.Format(f, a));

Address address = new Address("amqp://guest:guest@localhost:5672");
Connection connection = new Connection(address);
Session session = new Session(connection);

ReceiverLink receiver = new ReceiverLink(session, "receiver-link", "q1");
Message response = receiver.Receive();

Start the client:

dotnet run
[05:08:26.761] SEND AMQP 3 1 0 0
[05:08:26.804] RECV sasl-mechanisms(sasl-server-mechanisms:[ANONYMOUS,PLAIN,AMQPLAIN])
[05:08:26.806] SEND sasl-init(mechanism:PLAIN,initial-response:...,hostname:localhost)
[05:08:26.807] RECV sasl-outcome(code:Ok)
[05:08:26.808] SEND AMQP 0 1.0.0
[05:08:26.809] SEND (ch=0) open(container-id:AMQPNetLite-7ec36d4f,host-name:localhost,max-frame-size:262144,channel-max:255,idle-time-out:1073741823)
[05:08:26.809] RECV AMQP 0 1 0 0
[05:08:26.810] SEND (ch=0) begin(next-outgoing-id:4294967293,incoming-window:2048,outgoing-window:2048,handle-max:1023)
[05:08:26.811] SEND (ch=0) attach(name:receiver-link,handle:0,role:True,source:source(address:q1),target:target())
[05:08:26.812] SEND (ch=0) flow(next-in-id:0,in-window:2048,next-out-id:4294967293,out-window:2048,handle:0,delivery-count:0,link-credit:200,drain:False)
[05:08:26.815] RECV (ch=0) open(container-id:rabbit@myhost,max-frame-size:262144,channel-max:255,idle-time-out:60000,properties:[cluster_name:rabbit@myhost,copyright:Copyright (c) 2007-2023 VMware, Inc. or its affiliates.,information:Licensed under the MPL 2.0. Website: https://rabbitmq.com,platform:Erlang/OTP 26.1.2,product:RabbitMQ,version:3.12.8])
[05:08:26.818] RECV (ch=0) begin(remote-channel:0,next-outgoing-id:0,incoming-window:65535,outgoing-window:65535,handle-max:1023)
[05:08:26.819] RECV (ch=0) attach(name:receiver-link,handle:0,role:False,snd-settle-mode:Unsettled,source:source(address:q1,default-outcome:released(),outcomes:[amqp:accepted:list,amqp:rejected:list,amqp:released:list,amqp:modified:list]),initial-delivery-count:0)
[05:08:26.820] RECV (ch=0) flow(next-in-id:4294967293,in-window:65535,next-out-id:0,out-window:65535,handle:0,delivery-count:0,link-credit:200,available:0,drain:False)

As seen in the trace output, the client sends flow(next-in-id:0 before it receives the begin. Instead of setting next-in-id to 0, the correct behaviour is to not set that field.

ansd commented 7 months ago

Many thanks @xinchen10 for fixing this bug on master branch.

Would it be possible to release a new version of this library?

Alternatively, how do I specify to use master branch in the PackageReference Version in https://github.com/rabbitmq/rabbitmq-server/blob/48793d52888cd6900f1d604eebb6e390447880fe/deps/rabbitmq_amqp1_0/test/system_SUITE_data/fsharp-tests/fsharp-tests.fsproj#L11 ? Reading https://learn.microsoft.com/en-us/nuget/concepts/package-versioning this does not seem to be possible?

xinchen10 commented 6 months ago

We will release a new package soon. I don't think PackageReference can be used to reference source code from github repo branch. One way I can think of is the git submodule, which means you directly pull the code into your source tree and use project reference instead.