eclipse / paho.mqtt-sn.embedded-c

Paho C MQTT-SN gateway and libraries for embedded systems. Paho is an Eclipse IoT project.
https://eclipse.org/paho
Other
314 stars 179 forks source link

Send DISCONNECT when incoming message can't be mapped to a client #222

Closed vera closed 3 years ago

vera commented 3 years ago

The MQTT-SN spec (v1.2, p. 17) states:

A server or gateway may also sends a DISCONNECT to a client, e.g. in case a gateway, due to an error, cannot map a received message to a client. Upon receiving such a DISCONNECT message, a client should try to setup the connection again by sending a CONNECT message to the gateway or server. In all these cases the DISCONNECT message does not contain the Duration field.

Currently, the gateway only prints an error message but does not react in any other way to incoming messages (e.g. SUBSCRIBE, PUBLISH) that it can't map to a client. For example, this is the case when the client's IP address has changed since the connection was established. Since the client expects a response from the gateway, this leads to the client retransmitting the request and finally timing out (p. 25):

After N_{retry} retransmissions, the client aborts the procedure and assumes that its MQTT-SN connection to the gateway is disconnected. It should then try to connect to another gateway, and only if it fails to re-connect again to the former gateway.

With this change, the gateway sends a DISCONNECT message to the unknown client. The client is then able to re-CONNECT with the new IP address.

(I have not signed the ECA yet. if this is something that could be merged, I will try to get that done.)

vera commented 3 years ago

Looking through the file history, I just saw that this feature was included previously but then removed here:

https://github.com/eclipse/paho.mqtt-sn.embedded-c/commit/df080f28510e948ec09735393a6f23834cedf065#diff-bc1e2659848bfd92903b9baedc17ded712a11feaa665627a9fea3b2894e917faL224

Why was it removed?

ty4tw commented 3 years ago

Hi,

I will fix this as follows:

const char DisconectErrMsg[] = "%s MQTTSNGWClientRecvTask  Client(%s) is not connecting. message has been discarded.%s\n";

around line 160:

            if (client == nullptr)
            {
                client = _gateway->getClientList()->getClient(senderAddr);
            }
        }

        if (client != nullptr)
        {
            log(client, packet, 0);

            if (client->isDisconnect() && packet->getType() != MQTTSN_CONNECT)
            {
                WRITELOG(DisconectErrMsg, ERRMSG_HEADER,
                        senderAddr->sprint(buf), ERRMSG_FOOTER);

                /* send DISCONNECT to the client, if it is not connected */
                MQTTSNPacket* snPacket = new MQTTSNPacket();
                snPacket->setDISCONNECT(0);
                Event* ev1 = new Event();
                ev1->setClientSendEvent(client, snPacket);
                delete packet;
                continue;
            }
            else
            {
                ev = new Event();
                ev->setClientRecvEvent(client, packet);
                packetEventQue->post(ev);
            }
        }
        else
        {
            /* new client */
            if (packet->getType() == MQTTSN_CONNECT)
            {