zeromq / netmq

A 100% native C# implementation of ZeroMQ for .NET
Other
2.97k stars 744 forks source link

Calling Subscribe() multiple times on the XPublisher socket #925

Open nitrixx opened 4 years ago

nitrixx commented 4 years ago

Environment

NetMQ Version: 4.0.1.4
Operating System: Windows 10 
.NET Version: .NET Core 3.1

I am trying to implement token-based pubsub just like in this tutorial: https://somdoron.com/2014/12/token-pubsub/. The follow-up on this tutorial covers a heartbeat that is published to a dedicated topic. I am trying to automatically subscribe clients to the heartbeat topic while handling their initial subscription request (Since I am using a XSub socket on the client side this should not be a problem I think). The control flow should go something like this:

  1. Validate the provided JWT and read the desired topic from the contents of the JWT.
  2. Subscribe the client to the desired topic as well as the heartbeat topic

The problem I am facing is that the second call to Subscribe fails with an error: "NetMQ.InvalidException: Options.SetSocketOption called with invalid ZmqSocketOption of Subscribe". Is it not possible to call Subscribe() multiple times while handling a single request?

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had activity for 365 days. It will be closed if no further activity occurs within 56 days. Thank you for your contributions.

nateonthenet commented 2 years ago

It appears this issue can occur if you have an XPublisher socket that recieves a subscription request and you send another message on the socket before trying to activate the subscription with socket.Subscribe(topic).

In this case, m_lastPipe inside the XPub will be nulled out by the XPub.XSend method, and subsequent calls to XPublisher.Subscribe will then fail because of this bit of code inside the XPub.SetSocketOption method:

                {
                    if (m_manual && m_lastPipe != null)
                    {
                        var subscription = optionValue as byte[] ?? Encoding.ASCII.GetBytes(Get<string>());
                        m_subscriptions.Add(subscription, m_lastPipe);
                        m_lastPipe = null;
                        return true;
                    }
                    break;
                }

If m_lastPipe is null here, the behavior is exactly the same as if XSetSocketOption was still the virtual base method in SocketBase.XSetSocketOption (which just returns false), and as a result, you get a very misleading error: Options.SetSocketOption called with invalid ZmqSocketOption of Subscribe