zeromq / netmq

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

PubSub subscriber with curve security across processes doesn't receive messages #1066

Closed prkemp closed 1 year ago

prkemp commented 1 year ago

NetMQ Version: 4.0.1.12 Operating System: Windows 10 .NET Version: 6.0 LTS

Based on example presented in https://github.com/zeromq/netmq/issues/910, I've tried to split the publisher and subscriber across different processes. Both sockets are configured for Curve security (the subscriber[client] uses the publisher[server] public key).

Run the server and client, below, in separate processes. The client doesn't receive any messages when Curve security is configured. If security is disabled, the messages are received by the subscriber as expected.

Is this an issue with the library, or is the code wrong?

Thanks

Server code:

    using NetMQ;
    using NetMQ.Sockets;
    using System.Text;

    var publicPassword = "PUBLICsomearbitrarypassphrasethatwillbeusedasthepublickey";
    var secretPassword = "PRIVATEsomearbitrarypassphrasethatwillbeusedastheprivatekey";
    var publicKeyBytes = Encoding.ASCII.GetBytes(publicPassword).Take(32).ToArray();
    var secretKeyBytes = Encoding.ASCII.GetBytes(secretPassword).Take(32).ToArray();
    var serverPair = new NetMQCertificate(secretKeyBytes, publicKeyBytes);

    Random rand = new Random(50);
    using (var pubSocket = new PublisherSocket())
    {
        pubSocket.Options.CurveServer = true;    
        pubSocket.Options.CurveCertificate = serverPair;

        Console.WriteLine("Publisher socket binding...");
        pubSocket.Options.SendHighWatermark = 1000;
        pubSocket.Bind(@"tcp://localhost:12345");

        for (var i = 0; i < 100; i++)
        {
            var randomizedTopic = rand.NextDouble();
            var msg = new NetMQMessage();

            if (randomizedTopic > 0.5)
            {
                var msgContent = "TopicA msg-" + i;
                msg.Append("TopicA");
                msg.Append(msgContent);
                Console.WriteLine("Sending message : {0}", msgContent);
            }
            else
            {
                var msgContent = "TopicB msg-" + i;
                msg.Append("TopicB");
                msg.Append(msgContent);
                Console.WriteLine("Sending message : {0}", msgContent);
            }

            pubSocket.SendMultipartMessage(msg);
            Thread.Sleep(500);
        }
    }

Client code:

    using NetMQ;
    using NetMQ.Sockets;
    using System.Text;

    var publicPassword = "PUBLICsomearbitrarypassphrasethatwillbeusedasthepublickey";
    var publicKeyBytes = Encoding.ASCII.GetBytes(publicPassword).Take(32).ToArray();
    var clientPair = new NetMQCertificate();

    using (var subSocket = new SubscriberSocket())
    {    
        subSocket.Options.CurveServerKey = publicKeyBytes;
        subSocket.Options.CurveCertificate = clientPair;
        subSocket.Options.ReceiveHighWatermark = 1000;
        subSocket.Connect(@"tcp://localhost:12345");
        subSocket.SubscribeToAnyTopic();
        Console.WriteLine("Subscriber socket connecting...");
        while (true)
        {        
            var response = subSocket.ReceiveMultipartMessage();
            var messageReceived = response.Last.ConvertToString();
            Console.WriteLine(messageReceived);
        }
    }
prkemp commented 1 year ago

Figured out what I was doing wrong. You can't just make up your own arbitrary public/private key. They have to be generated as a pair, which you can do using new NetMQCertificate(), then safe the public key down to a file, which the subscriber process(es) can use.

I hope my experience helps others!