public MQTTConnection create(Channel channel) { return new MQTTConnection(channel, brokerConfig, authenticator, sessionRegistry, postOffice); } }
public void resendNotAckedPublishes() { final Session session = sessionRegistry.retrieve(getClientId()); session.resendInflightNotAcked(); }
@Override public void channelInactive(ChannelHandlerContext ctx) { final MQTTConnection mqttConnection = mqttConnection(ctx.channel()); mqttConnection.handleConnectionLost(); }
switch (messageType) { case CONNECT: processConnect((MqttConnectMessage) msg); break; case SUBSCRIBE: processSubscribe((MqttSubscribeMessage) msg); break; case UNSUBSCRIBE: processUnsubscribe((MqttUnsubscribeMessage) msg); break; case PUBLISH: processPublish((MqttPublishMessage) msg); break; case PUBREC: processPubRec(msg); break; case PUBCOMP: processPubComp(msg); break; case PUBREL: processPubRel(msg); break; case DISCONNECT: processDisconnect(msg); break; case PUBACK: processPubAck(msg); break; case PINGREQ:
private void processPubRel(MqttMessage msg) { final Session session = sessionRegistry.retrieve(getClientId()); final int messageID = ((MqttMessageIdVariableHeader) msg.variableHeader()).messageId(); session.receivedPubRelQos2(messageID); sendPubCompMessage(messageID); }
LOG.trace("Processing CONNECT message. CId={} username: {} channel: {}", clientId, username, channel); if (isNotProtocolVersion(msg, MqttVersion.MQTT_3_1) && isNotProtocolVersion(msg, MqttVersion.MQTT_3_1_1)) { LOG.warn("MQTT protocol version is not valid. CId={} channel: {}", clientId, channel); abortConnection(CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION); return; if (!brokerConfig.isAllowZeroByteClientId()) { LOG.warn("Broker doesn't permit MQTT empty client ID. Username: {}, channel: {}", username, channel); abortConnection(CONNECTION_REFUSED_IDENTIFIER_REJECTED); return; LOG.warn("MQTT client ID cannot be empty for persistent session. Username: {}, channel: {}", username, channel); abortConnection(CONNECTION_REFUSED_IDENTIFIER_REJECTED); return; if (!login(msg, clientId)) { abortConnection(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD); channel.close().addListener(CLOSE_ON_FAILURE); return; initializeKeepAliveTimeout(channel, msg, clientId); setupInflightResender(channel); } catch (SessionCorruptedException scex) { LOG.warn("MQTT session for client ID {} cannot be created, channel: {}", clientId, channel); abortConnection(CONNECTION_REFUSED_SERVER_UNAVAILABLE);
@Test public void avoidMultipleNotificationsAfterMultipleReconnection_cleanSessionFalseQoS1() { final MqttConnectMessage notCleanConnect = ConnectionTestUtils.buildConnectNotClean(FAKE_CLIENT_ID); connect(connection, notCleanConnect); subscribe(connection, NEWS_TOPIC, AT_LEAST_ONCE); connection.processDisconnect(null); // connect on another channel final String firstPayload = "Hello MQTT 1"; connectPublishDisconnectFromAnotherClient(firstPayload, NEWS_TOPIC); // reconnect FAKE_CLIENT on another channel EmbeddedChannel anotherChannel2 = new EmbeddedChannel(); MQTTConnection anotherConnection2 = createMQTTConnection(CONFIG, anotherChannel2); anotherConnection2.processConnect(notCleanConnect); ConnectionTestUtils.assertConnectAccepted(anotherChannel2); ConnectionTestUtils.verifyPublishIsReceived(anotherChannel2, MqttQoS.AT_LEAST_ONCE, firstPayload); anotherConnection2.processDisconnect(null); final String secondPayload = "Hello MQTT 2"; connectPublishDisconnectFromAnotherClient(secondPayload, NEWS_TOPIC); EmbeddedChannel anotherChannel3 = new EmbeddedChannel(); MQTTConnection anotherConnection3 = createMQTTConnection(CONFIG, anotherChannel3); anotherConnection3.processConnect(notCleanConnect); ConnectionTestUtils.assertConnectAccepted(anotherChannel3); ConnectionTestUtils.verifyPublishIsReceived(anotherChannel3, MqttQoS.AT_LEAST_ONCE, secondPayload); }
protected void connect(MQTTConnection connection, MqttConnectMessage connectMessage) { connection.processConnect(connectMessage); ConnectionTestUtils.assertConnectAccepted((EmbeddedChannel) connection.channel); }
connection.processConnect(connectMessage); ConnectionTestUtils.assertConnectAccepted(channel); assertEquals("After CONNECT subscription MUST be empty", 0, subscriptions.size()); .messageId(1) .build(); connection.processSubscribe(subscribeMsg); assertEquals("Subscribe MUST contain one subscription", 1, subscriptions.size()); connection.processDisconnect(null); assertEquals("Disconnection MUSTN'T clear subscriptions", 1, subscriptions.size()); channel = new EmbeddedChannel(); connection = createMQTTConnection(CONFIG, channel); connection.processConnect(connectMessage); ConnectionTestUtils.assertConnectAccepted(channel); assertEquals("After CONNECT with clean, subscription MUST be empty", 0, subscriptions.size());
@Test public void testZeroByteClientIdWithCleanSession() { // Connect message with clean session set to true and client id is null. MqttConnectMessage msg = MqttMessageBuilders.connect() .protocolVersion(MqttVersion.MQTT_3_1_1) .clientId(null) .cleanSession(true) .build(); sut.processConnect(msg); assertEqualsConnAck("Connection must be accepted", CONNECTION_ACCEPTED, channel.readOutbound()); assertNotNull("unique clientid must be generated", sut.getClientId()); assertTrue("clean session flag must be true", sessionRegistry.retrieve(sut.getClientId()).isClean()); assertTrue("Connection must be open", channel.isOpen()); }
@Test public void testWillIsFired() { final PostOffice postOfficeMock = mock(PostOffice.class); sut = createMQTTConnectionWithPostOffice(CONFIG, postOfficeMock); channel = (EmbeddedChannel) sut.channel; MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID).willFlag(true) .willTopic("topic").willMessage("Topic message").build(); sut.processConnect(msg); // Exercise sut.handleConnectionLost(); // Verify verify(postOfficeMock).fireWill(any(Session.Will.class)); assertFalse("Connection MUST be disconnected", sut.isConnected()); }
public void unsubscribe(List<String> topics, MQTTConnection mqttConnection, int messageId) { final String clientID = mqttConnection.getClientId(); for (String t : topics) { Topic topic = new Topic(t); boolean validTopic = topic.isValid(); if (!validTopic) { // close the connection, not valid topicFilter is a protocol violation mqttConnection.dropConnection(); LOG.warn("Topic filter is not valid. CId={}, topics: {}, offending topic filter: {}", clientID, topics, topic); return; } LOG.trace("Removing subscription. CId={}, topic={}", clientID, topic); subscriptions.removeSubscription(topic, clientID); // TODO remove the subscriptions to Session // clientSession.unsubscribeFrom(topic); String username = NettyUtils.userName(mqttConnection.channel); interceptor.notifyTopicUnsubscribed(topic.toString(), clientID, username); } // ack the client mqttConnection.sendUnsubAckMessage(topics, clientID, messageId); }
void receivedPublishQos1(MQTTConnection connection, Topic topic, String username, ByteBuf payload, int messageID, boolean retain, MqttPublishMessage msg) { // verify if topic can be write topic.getTokens(); if (!topic.isValid()) { LOG.warn("Invalid topic format, force close the connection"); connection.dropConnection(); return; } final String clientId = connection.getClientId(); if (!authorizator.canWrite(topic, username, clientId)) { LOG.error("MQTT client: {} is not authorized to publish on topic: {}", clientId, topic); return; } publish2Subscribers(payload, topic, AT_LEAST_ONCE); connection.sendPubAck(messageID); if (retain) { if (!payload.isReadable()) { retainedRepository.cleanRetained(topic); } else { // before wasn't stored retainedRepository.retain(topic, msg); } } interceptor.notifyTopicPublished(msg, clientId, username); }
private void connectPublishDisconnectFromAnotherClient(String firstPayload, String topic) { MQTTConnection anotherConnection = connectNotCleanAs(PUBLISHER_ID); // publish from another channel final ByteBuf anyPayload = Unpooled.copiedBuffer(firstPayload, Charset.defaultCharset()); sut.receivedPublishQos1(anotherConnection, new Topic(topic), TEST_USER, anyPayload, 1, false, MqttMessageBuilders.publish() .payload(Unpooled.copiedBuffer(firstPayload, Charset.defaultCharset())) .qos(MqttQoS.AT_LEAST_ONCE) .retained(false) .topicName(topic).build()); // disconnect the other channel anotherConnection.processDisconnect(null); }
void sendPublish(MqttPublishMessage publishMsg) { final int packetId = publishMsg.variableHeader().packetId(); final String topicName = publishMsg.variableHeader().topicName(); final String clientId = getClientId(); MqttQoS qos = publishMsg.fixedHeader().qosLevel(); if (LOG.isTraceEnabled()) { LOG.trace("Sending PUBLISH({}) message. MessageId={}, CId={}, topic={}, payload={}", qos, packetId, clientId, topicName, DebugUtils.payload2Str(publishMsg.payload())); } else { LOG.debug("Sending PUBLISH({}) message. MessageId={}, CId={}, topic={}", qos, packetId, clientId, topicName); } sendIfWritableElseDrop(publishMsg); }
final String username = NettyUtils.userName(channel); final String topicName = msg.variableHeader().topicName(); final String clientId = getClientId(); LOG.trace("Processing PUBLISH message. CId={}, topic: {}, messageId: {}, qos: {}", clientId, topicName, msg.variableHeader().packetId(), qos); if (!topic.isValid()) { LOG.debug("Drop connection because of invalid topic format"); dropConnection();
@Test public void dropConnectionOnPublishWithInvalidTopicFormat() { // Connect message with clean session set to true and client id is null. MqttPublishMessage publish = MqttMessageBuilders.publish() .topicName("") .retained(false) .qos(MqttQoS.AT_MOST_ONCE) .payload(Unpooled.copiedBuffer("Hello MQTT world!".getBytes(UTF_8))).build(); sut.processPublish(publish); // Verify assertFalse("Connection should be closed by the broker", channel.isOpen()); }
void sendConnAck(boolean isSessionAlreadyPresent) { connected = true; final MqttConnAckMessage ackMessage = connAck(CONNECTION_ACCEPTED, isSessionAlreadyPresent); channel.writeAndFlush(ackMessage).addListener(FIRE_EXCEPTION_ON_FAILURE); }
public void closeImmediately() { mqttConnection.dropConnection(); }
@Test public void noPublishToInactiveSession() { // create an inactive session for Subscriber connection.processConnect(ConnectionTestUtils.buildConnectNotClean(SUBSCRIBER_ID)); ConnectionTestUtils.assertConnectAccepted(channel); subscribe(connection, NEWS_TOPIC, AT_LEAST_ONCE); connection.processDisconnect(null); // Exercise EmbeddedChannel pubChannel = new EmbeddedChannel(); MQTTConnection pubConn = createMQTTConnection(ALLOW_ANONYMOUS_AND_ZERO_BYTES_CLID, pubChannel); pubConn.processConnect(ConnectionTestUtils.buildConnect(PUBLISHER_ID)); ConnectionTestUtils.assertConnectAccepted(pubChannel); final ByteBuf anyPayload = Unpooled.copiedBuffer("Any payload", Charset.defaultCharset()); sut.receivedPublishQos1(pubConn, new Topic(NEWS_TOPIC), TEST_USER, anyPayload, 1, true, MqttMessageBuilders.publish() .payload(anyPayload) .qos(MqttQoS.AT_LEAST_ONCE) .retained(true) .topicName(NEWS_TOPIC).build()); verifyNoPublishIsReceived(channel); }