/** * Utility function to start a new publish exchange. * @param pubclient the client to send the publication to * @param publish the publication data * @param qos the MQTT QoS to use * @param retained boolean - whether to set the MQTT retained flag * @return the completion code */ int MQTTProtocol_startPublishCommon(Clients* pubclient, Publish* publish, int qos, int retained) { int rc = TCPSOCKET_COMPLETE; FUNC_ENTRY; if (qos == 0 && (strlen(publish->topic) < 5 || strncmp(publish->topic, sysprefix, strlen(sysprefix)) != 0)) { ++(bstate->msgs_sent); bstate->bytes_sent += publish->payloadlen; } #if defined(MQTTS) if (pubclient->protocol == PROTOCOL_MQTTS) { rc = MQTTSProtocol_startPublishCommon(pubclient,publish,0,qos,retained); } else { #endif rc = MQTTPacket_send_publish(publish, 0, qos, retained, pubclient->socket, pubclient->clientID); if (qos == 0 && rc == TCPSOCKET_INTERRUPTED) MQTTProtocol_storeQoS0(pubclient, publish); #if defined(MQTTS) } #endif FUNC_EXIT_RC(rc); return rc; }
/** * Utility function to start a new publish exchange. * @param pubclient the client to send the publication to * @param publish the publication data * @param qos the MQTT QoS to use * @param retained boolean - whether to set the MQTT retained flag * @return the completion code */ static int MQTTProtocol_startPublishCommon(Clients* pubclient, Publish* publish, int qos, int retained) { int rc = TCPSOCKET_COMPLETE; FUNC_ENTRY; rc = MQTTPacket_send_publish(publish, 0, qos, retained, &pubclient->net, pubclient->clientID); if (qos == 0 && rc == TCPSOCKET_INTERRUPTED) MQTTProtocol_storeQoS0(pubclient, publish); FUNC_EXIT_RC(rc); return rc; }
/** * MQTT retry processing per client * @param now current time * @param client - the client to which to apply the retry processing */ void MQTTProtocol_retries(time_t now, Clients* client) { ListElement* outcurrent = NULL; FUNC_ENTRY; #if defined(MQTTS) if (client->protocol == PROTOCOL_MQTTS) { if (client->pendingRegistration != NULL && difftime(now, client->pendingRegistration->sent) > bstate->retry_interval) { Registration* reg = client->pendingRegistration->registration; time(&client->pendingRegistration->sent); /* NB: no dup bit for these packets */ if (MQTTSPacket_send_register(client, reg->id, reg->topicName, client->pendingRegistration->msgId) == SOCKET_ERROR) { client->good = 0; //TODO: update message Log(LOG_WARNING, 29, NULL, client->clientID, client->socket); MQTTProtocol_closeSession(client, 1); client = NULL; } } #if !defined(NO_BRIDGE) if (client->pendingSubscription != NULL && difftime(now, client->pendingSubscription->sent) > bstate->retry_interval) { time(&client->pendingSubscription->sent); if (MQTTSPacket_send_subscribe(client, client->pendingSubscription->topicName,client->pendingSubscription->qos, client->pendingSubscription->msgId) == SOCKET_ERROR) { client->good = 0; //TODO: update message Log(LOG_WARNING, 29, NULL, client->clientID, client->socket); MQTTProtocol_closeSession(client, 1); client = NULL; } } #endif } #endif while (client && ListNextElement(client->outboundMsgs, &outcurrent) && client->connected && client->good && /* client is connected and has no errors */ Socket_noPendingWrites(client->socket)) /* there aren't any previous packets still stacked up on the socket */ { Messages* m = (Messages*)(outcurrent->content); if (difftime(now, m->lastTouch) > bstate->retry_interval) { if (m->qos == 1 || (m->qos == 2 && m->nextMessageType == PUBREC)) { Publish publish; int rc; Log(LOG_INFO, 28, NULL, client->clientID, client->socket, m->msgid); publish.msgId = m->msgid; publish.topic = m->publish->topic; publish.payload = m->publish->payload; publish.payloadlen = m->publish->payloadlen; #if defined(MQTTS) if (client->protocol == PROTOCOL_MQTTS) { if (MQTTSProtocol_startPublishCommon(client, &publish, 1, m->qos, m->retain) == SOCKET_ERROR) { client->good = 0; Log(LOG_WARNING, 29, NULL, client->clientID, client->socket); MQTTProtocol_closeSession(client, 1); client = NULL; } else time(&(m->lastTouch)); } else { #endif rc = MQTTPacket_send_publish(&publish, 1, m->qos, m->retain, client->socket, client->clientID); if (rc == SOCKET_ERROR) { client->good = 0; Log(LOG_WARNING, 29, NULL, client->clientID, client->socket); MQTTProtocol_closeSession(client, 1); client = NULL; } else { if (m->qos == 0 && rc == TCPSOCKET_INTERRUPTED) MQTTProtocol_storeQoS0(client, &publish); time(&(m->lastTouch)); } #if defined(MQTTS) } #endif } else if (m->qos && m->nextMessageType == PUBCOMP) { Log(LOG_WARNING, 30, NULL, client->clientID, m->msgid); #if defined(MQTTS) if (client->protocol == PROTOCOL_MQTTS) { /* NB: no dup bit for PUBREL */ if (MQTTSPacket_send_pubrel(client, m->msgid) == SOCKET_ERROR) { client->good = 0; Log(LOG_WARNING, 18, NULL, client->clientID, client->socket, Socket_getpeer(client->socket)); MQTTProtocol_closeSession(client, 1); client = NULL; } else time(&(m->lastTouch)); } else #endif if (MQTTPacket_send_pubrel(m->msgid, 1, client->socket, client->clientID) != TCPSOCKET_COMPLETE) { client->good = 0; Log(LOG_WARNING, 18, NULL, client->clientID, client->socket, Socket_getpeer(client->socket)); MQTTProtocol_closeSession(client, 1); client = NULL; } else time(&(m->lastTouch)); } /* break; why not do all retries at once? */ } } FUNC_EXIT; }
/** * MQTT retry processing per client * @param now current time * @param client - the client to which to apply the retry processing * @param regardless boolean - retry packets regardless of retry interval (used on reconnect) */ static void MQTTProtocol_retries(time_t now, Clients* client, int regardless) { ListElement* outcurrent = NULL; FUNC_ENTRY; if (!regardless && client->retryInterval <= 0) /* 0 or -ive retryInterval turns off retry except on reconnect */ goto exit; while (client && ListNextElement(client->outboundMsgs, &outcurrent) && client->connected && client->good && /* client is connected and has no errors */ Socket_noPendingWrites(client->net.socket)) /* there aren't any previous packets still stacked up on the socket */ { Messages* m = (Messages*)(outcurrent->content); if (regardless || difftime(now, m->lastTouch) > max(client->retryInterval, 10)) { if (m->qos == 1 || (m->qos == 2 && m->nextMessageType == PUBREC)) { Publish publish; int rc; Log(TRACE_MIN, 7, NULL, "PUBLISH", client->clientID, client->net.socket, m->msgid); publish.msgId = m->msgid; publish.topic = m->publish->topic; publish.payload = m->publish->payload; publish.payloadlen = m->publish->payloadlen; rc = MQTTPacket_send_publish(&publish, 1, m->qos, m->retain, &client->net, client->clientID); if (rc == SOCKET_ERROR) { client->good = 0; Log(TRACE_PROTOCOL, 29, NULL, client->clientID, client->net.socket, Socket_getpeer(client->net.socket)); MQTTProtocol_closeSession(client, 1); client = NULL; } else { if (m->qos == 0 && rc == TCPSOCKET_INTERRUPTED) MQTTProtocol_storeQoS0(client, &publish); time(&(m->lastTouch)); } } else if (m->qos && m->nextMessageType == PUBCOMP) { Log(TRACE_MIN, 7, NULL, "PUBREL", client->clientID, client->net.socket, m->msgid); if (MQTTPacket_send_pubrel(m->msgid, 0, &client->net, client->clientID) != TCPSOCKET_COMPLETE) { client->good = 0; Log(TRACE_PROTOCOL, 29, NULL, client->clientID, client->net.socket, Socket_getpeer(client->net.socket)); MQTTProtocol_closeSession(client, 1); client = NULL; } else time(&(m->lastTouch)); } /* break; why not do all retries at once? */ } } exit: FUNC_EXIT; }