Beispiel #1
0
        public async Task MqttSubscriptionsManager_SubscribeAndUnsubscribeSingle()
        {
            var s = new MqttClientSession("", new ConcurrentDictionary <object, object>(),
                                          new MqttServerEventDispatcher(new TestLogger()), new MqttServerOptions(), new TestLogger());

            var sm = new MqttClientSubscriptionsManager(s, new MqttServerEventDispatcher(new TestLogger()), new MqttServerOptions());

            var sp = new MqttSubscribePacket();

            sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build());

            await sm.SubscribeAsync(sp, new MqttConnectPacket());

            Assert.IsTrue(sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce).IsSubscribed);

            var up = new MqttUnsubscribePacket();

            up.TopicFilters.Add("A/B/C");
            await sm.UnsubscribeAsync(up);

            Assert.IsFalse(sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce).IsSubscribed);
        }
Beispiel #2
0
        public MqttUnsubAckPacket Unsubscribe(MqttUnsubscribePacket unsubscribePacket)
        {
            if (unsubscribePacket == null)
            {
                throw new ArgumentNullException(nameof(unsubscribePacket));
            }

            lock (_subscriptions)
            {
                foreach (var topicFilter in unsubscribePacket.TopicFilters)
                {
                    _subscriptions.Remove(topicFilter);

                    _eventDispatcher.OnClientUnsubscribedTopic(_clientId, topicFilter);
                }
            }

            return(new MqttUnsubAckPacket
            {
                PacketIdentifier = unsubscribePacket.PacketIdentifier
            });
        }
Beispiel #3
0
        public void Serialize_Full_MqttUnsubscribePacket_V500()
        {
            var unsubscribePacket = new MqttUnsubscribePacket
            {
                PacketIdentifier = 123,
                TopicFilters     = new List <string>
                {
                    "TopicFilter1"
                },
                UserProperties = new List <MqttUserProperty>
                {
                    new MqttUserProperty("Foo", "Bar")
                }
            };

            var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(unsubscribePacket, MqttProtocolVersion.V500);

            Assert.AreEqual(unsubscribePacket.PacketIdentifier, deserialized.PacketIdentifier);
            Assert.AreEqual(unsubscribePacket.TopicFilters.Count, deserialized.TopicFilters.Count);
            Assert.AreEqual(unsubscribePacket.TopicFilters[0], deserialized.TopicFilters[0]);
            CollectionAssert.AreEqual(unsubscribePacket.UserProperties, deserialized.UserProperties);
        }
Beispiel #4
0
        public async Task <List <MqttUnsubscribeReasonCode> > UnsubscribeAsync(MqttUnsubscribePacket unsubscribePacket)
        {
            if (unsubscribePacket == null)
            {
                throw new ArgumentNullException(nameof(unsubscribePacket));
            }

            var reasonCodes = new List <MqttUnsubscribeReasonCode>();

            foreach (var topicFilter in unsubscribePacket.TopicFilters)
            {
                var interceptorContext = await InterceptUnsubscribeAsync(topicFilter).ConfigureAwait(false);

                if (!interceptorContext.AcceptUnsubscription)
                {
                    reasonCodes.Add(MqttUnsubscribeReasonCode.ImplementationSpecificError);
                    continue;
                }

                _subscriptionsLock.EnterWriteLock();
                try
                {
                    reasonCodes.Add(_subscriptions.Remove(topicFilter)
                        ? MqttUnsubscribeReasonCode.Success
                        : MqttUnsubscribeReasonCode.NoSubscriptionExisted);
                }
                finally
                {
                    _subscriptionsLock.ExitWriteLock();
                }
            }

            foreach (var topicFilter in unsubscribePacket.TopicFilters)
            {
                await _eventDispatcher.SafeNotifyClientUnsubscribedTopicAsync(_clientSession.ClientId, topicFilter).ConfigureAwait(false);
            }

            return(reasonCodes);
        }
        public MqttClientUnsubscribeResult CreateClientUnsubscribeResult(MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket)
        {
            if (unsubscribePacket == null)
            {
                throw new ArgumentNullException(nameof(unsubscribePacket));
            }
            if (unsubAckPacket == null)
            {
                throw new ArgumentNullException(nameof(unsubAckPacket));
            }

            if (unsubAckPacket.ReasonCodes.Count != unsubscribePacket.TopicFilters.Count)
            {
                throw new MqttProtocolViolationException("The return codes are not matching the topic filters [MQTT-3.9.3-1].");
            }

            var result = new MqttClientUnsubscribeResult();

            result.Items.AddRange(unsubscribePacket.TopicFilters.Select((t, i) =>
                                                                        new MqttClientUnsubscribeResultItem(t, (MqttClientUnsubscribeResultCode)unsubAckPacket.ReasonCodes[i])));

            return(result);
        }
Beispiel #6
0
        byte EncodeUnsubscribePacket(MqttUnsubscribePacket packet)
        {
            if (packet.TopicFilters?.Any() != true)
            {
                throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");
            }

            ThrowIfPacketIdentifierIsInvalid(packet.PacketIdentifier, packet);

            _bufferWriter.WriteTwoByteInteger(packet.PacketIdentifier);

            _propertiesWriter.WriteUserProperties(packet.UserProperties);

            _propertiesWriter.WriteTo(_bufferWriter);
            _propertiesWriter.Reset();

            foreach (var topicFilter in packet.TopicFilters)
            {
                _bufferWriter.WriteString(topicFilter);
            }

            return(MqttBufferWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02));
        }
        public async Task <MqttUnsubAckPacket> UnsubscribeAsync(MqttUnsubscribePacket unsubscribePacket)
        {
            if (unsubscribePacket == null)
            {
                throw new ArgumentNullException(nameof(unsubscribePacket));
            }

            await _semaphore.WaitAsync().ConfigureAwait(false);

            try
            {
                foreach (var topicFilter in unsubscribePacket.TopicFilters)
                {
                    _subscriptions.Remove(topicFilter);
                }
            }
            finally
            {
                _semaphore.Release();
            }

            return(unsubscribePacket.CreateResponse <MqttUnsubAckPacket>());
        }
Beispiel #8
0
        static byte EncodeUnsubscribePacket(MqttUnsubscribePacket packet, IMqttPacketWriter packetWriter)
        {
            if (!packet.TopicFilters.Any())
            {
                throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");
            }

            if (!packet.PacketIdentifier.HasValue)
            {
                throw new MqttProtocolViolationException("Unsubscribe packet has no packet identifier.");
            }

            packetWriter.Write(packet.PacketIdentifier.Value);

            if (packet.TopicFilters?.Any() == true)
            {
                foreach (var topicFilter in packet.TopicFilters)
                {
                    packetWriter.WriteWithLengthPrefix(topicFilter);
                }
            }

            return(MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02));
        }
Beispiel #9
0
        static byte EncodeUnsubscribePacket(MqttUnsubscribePacket packet, MqttBufferWriter bufferWriter)
        {
            if (!packet.TopicFilters.Any())
            {
                throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");
            }

            if (packet.PacketIdentifier == 0)
            {
                throw new MqttProtocolViolationException("Unsubscribe packet has no packet identifier.");
            }

            bufferWriter.WriteTwoByteInteger(packet.PacketIdentifier);

            if (packet.TopicFilters?.Any() == true)
            {
                foreach (var topicFilter in packet.TopicFilters)
                {
                    bufferWriter.WriteString(topicFilter);
                }
            }

            return(MqttBufferWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02));
        }
        private void HandleIncomingUnsubscribePacket(IMqttChannelAdapter adapter, MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
        {
            var unsubscribeResult = _subscriptionsManager.Unsubscribe(unsubscribePacket);

            adapter.SendPacketAsync(unsubscribeResult, cancellationToken).GetAwaiter().GetResult();
        }
        private async Task HandleIncomingUnsubscribePacketAsync(IMqttChannelAdapter adapter, MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
        {
            var unsubscribeResult = await _subscriptionsManager.UnsubscribeAsync(unsubscribePacket);

            await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, unsubscribeResult);
        }
Beispiel #12
0
        static MqttClientUnsubscribeResultItem CreateUnsubscribeResultItem(int index, MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket)
        {
            var resultCode = MqttClientUnsubscribeResultCode.Success;

            if (unsubAckPacket.ReasonCodes != null)
            {
                // MQTTv3.1.1 has no reason code and no return code!.
                resultCode = (MqttClientUnsubscribeResultCode)unsubAckPacket.ReasonCodes[index];
            }

            return(new MqttClientUnsubscribeResultItem
            {
                TopicFilter = unsubscribePacket.TopicFilters[index],
                ResultCode = resultCode
            });
        }
        public async Task <MqttUnsubscribeResult> Unsubscribe(MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
        {
            if (unsubscribePacket == null)
            {
                throw new ArgumentNullException(nameof(unsubscribePacket));
            }

            var result = new MqttUnsubscribeResult();

            var removedSubscriptions = new List <string>();

            await _subscriptionsLock.WaitAsync(cancellationToken).ConfigureAwait(false);

            try
            {
                foreach (var topicFilter in unsubscribePacket.TopicFilters)
                {
                    _subscriptions.TryGetValue(topicFilter, out var existingSubscription);

                    var interceptorContext = await InterceptUnsubscribe(topicFilter, existingSubscription, cancellationToken).ConfigureAwait(false);

                    var acceptUnsubscription = interceptorContext.Response.ReasonCode == MqttUnsubscribeReasonCode.Success;

                    result.ReasonCodes.Add(interceptorContext.Response.ReasonCode);

                    if (interceptorContext.CloseConnection)
                    {
                        // When any of the interceptor calls leads to a connection close the connection
                        // must be closed. So do not revert to false!
                        result.CloseConnection = true;
                    }

                    if (!acceptUnsubscription)
                    {
                        continue;
                    }

                    if (interceptorContext.ProcessUnsubscription)
                    {
                        _subscriptions.Remove(topicFilter);

                        // must remove subscription object from topic hash dictionary also

                        if (existingSubscription.TopicHasWildcard)
                        {
                            if (_wildcardSubscriptionsByTopicHash.TryGetValue(existingSubscription.TopicHash, out var subs))
                            {
                                subs.Subscriptions.Remove(existingSubscription);
                                if (subs.Subscriptions.Count == 0)
                                {
                                    _wildcardSubscriptionsByTopicHash.Remove(existingSubscription.TopicHash);
                                }
                            }
                        }
                        else
                        {
                            if (_noWildcardSubscriptionsByTopicHash.TryGetValue(existingSubscription.TopicHash, out var subs))
                            {
                                subs.Remove(existingSubscription);
                                if (subs.Count == 0)
                                {
                                    _noWildcardSubscriptionsByTopicHash.Remove(existingSubscription.TopicHash);
                                }
                            }
                        }

                        removedSubscriptions.Add(topicFilter);
                    }
                }
            }
            finally
            {
                _subscriptionsLock.Release();

                if (_subscriptionChangedNotification != null)
                {
                    _subscriptionChangedNotification.OnSubscriptionsRemoved(_session, removedSubscriptions);
                }
            }

            if (_eventContainer.ClientUnsubscribedTopicEvent.HasHandlers)
            {
                foreach (var topicFilter in unsubscribePacket.TopicFilters)
                {
                    var eventArgs = new ClientUnsubscribedTopicEventArgs
                    {
                        ClientId    = _session.Id,
                        TopicFilter = topicFilter
                    };

                    await _eventContainer.ClientUnsubscribedTopicEvent.InvokeAsync(eventArgs).ConfigureAwait(false);
                }
            }

            return(result);
        }