static void DoTimeouts(IOTHUB_CLIENT_LL_HANDLE_DATA* handleData) { uint64_t nowTick; if (tickcounter_get_current_ms(handleData->tickCounter, &nowTick) != 0) { LogError("unable to get the current ms, timeouts will not be processed"); } else { DLIST_ENTRY* currentItemInWaitingToSend = handleData->waitingToSend.Flink; while (currentItemInWaitingToSend != &(handleData->waitingToSend)) /*while we are not at the end of the list*/ { IOTHUB_MESSAGE_LIST* fullEntry = containingRecord(currentItemInWaitingToSend, IOTHUB_MESSAGE_LIST, entry); /*Codes_SRS_IOTHUBCLIENT_LL_02_041: [ If more than value miliseconds have passed since the call to IoTHubClient_LL_SendEventAsync then the message callback shall be called with a status code of IOTHUB_CLIENT_CONFIRMATION_TIMEOUT. ]*/ if ((fullEntry->ms_timesOutAfter != 0) && (fullEntry->ms_timesOutAfter < nowTick)) { PDLIST_ENTRY theNext = currentItemInWaitingToSend->Flink; /*need to save the next item, because the below operations are destructive*/ DList_RemoveEntryList(currentItemInWaitingToSend); if (fullEntry->callback != NULL) { fullEntry->callback(IOTHUB_CLIENT_CONFIRMATION_MESSAGE_TIMEOUT, fullEntry->context); } IoTHubMessage_Destroy(fullEntry->messageHandle); /*because it has been cloned*/ free(fullEntry); currentItemInWaitingToSend = theNext; } else { currentItemInWaitingToSend = currentItemInWaitingToSend->Flink; } } } }
static void delivered(void *context, MQTTClient_deliveryToken dt) { PMQTTTAPI_HANDLE_DATA transportState = (PMQTTTAPI_HANDLE_DATA)context; if (context != NULL) { //First try to find the message on the list. PDLIST_ENTRY currentListEntry; currentListEntry = transportState->messagesSent.Flink; if (currentListEntry != NULL) { while (currentListEntry != &transportState->messagesSent) { MQTTAPI_MESSAGE_SEND_LIST *mqttMessageDetailEntry = containingRecord(currentListEntry, MQTTAPI_MESSAGE_SEND_LIST, entry); //Identify here if the message is the one arrived. if (mqttMessageDetailEntry->dt == dt) { (void)DList_RemoveEntryList(currentListEntry); //First remove the item from Waiting for Ack List. if (transportState->dcCallback != NULL) { /* Codes_SRS_MQTTAPI_04_009: [The context parameter is a point to the original value passed by MQTTAPI_PublishMessage, which contains message-specific context.] */ /* Codes_SRS_MQTTAPI_04_052: [result contains the status of the message sent by publish.] */ transportState->dcCallback(mqttMessageDetailEntry->context, MQTTAPI_CONFIRMATION_OK); } STRING_delete(mqttMessageDetailEntry->topicName); MQTTClient_freeMessage(&(mqttMessageDetailEntry->messageToSend)); free(mqttMessageDetailEntry); break; } currentListEntry = currentListEntry->Flink; } } else { LogError("Error trying to access items on messagesSEnt list. Possible not initialized List.\r\n"); } } }
extern void IoTHubTransportMqtt_DoWork(TRANSPORT_HANDLE handle, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle) { /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_026: [IoTHubTransportMqtt_DoWork shall do nothing if parameter handle and/or iotHubClientHandle is NULL.] */ PMQTTTRANSPORT_HANDLE_DATA transportState = (PMQTTTRANSPORT_HANDLE_DATA)handle; if (transportState != NULL && iotHubClientHandle != NULL) { transportState->llClientHandle = iotHubClientHandle; if (InitializeConnection(transportState, true) != 0) { // Don't want to flood the logs with failures here } else { if (transportState->currPacketState == CONNACK_TYPE) { (void)SubscribeToMqttProtocol(transportState); } else if (transportState->currPacketState == SUBACK_TYPE) { // Publish can be called now transportState->currPacketState = PUBLISH_TYPE; } else if (transportState->currPacketState == PUBLISH_TYPE) { PDLIST_ENTRY currentListEntry = transportState->waitingForAck.Flink; while (currentListEntry != &transportState->waitingForAck) { MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry = containingRecord(currentListEntry, MQTT_MESSAGE_DETAILS_LIST, entry); DLIST_ENTRY nextListEntry; nextListEntry.Flink = currentListEntry->Flink; uint64_t current_ms; (void)tickcounter_get_current_ms(g_msgTickCounter, ¤t_ms); /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_033: [IoTHubTransportMqtt_DoWork shall iterate through the Waiting Acknowledge messages looking for any message that has been waiting longer than 2 min.]*/ if (((current_ms - mqttMsgEntry->msgPublishTime) / 1000) > RESEND_TIMEOUT_VALUE_MIN) { /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_034: [If IoTHubTransportMqtt_DoWork has resent the message two times then it shall fail the message] */ if (mqttMsgEntry->retryCount >= MAX_SEND_RECOUNT_LIMIT) { (void)DList_RemoveEntryList(currentListEntry); sendMsgComplete(mqttMsgEntry->iotHubMessageEntry, transportState, IOTHUB_BATCHSTATE_FAILED); free(mqttMsgEntry); } else { size_t messageLength; const unsigned char* messagePayload = RetrieveMessagePayload(mqttMsgEntry->iotHubMessageEntry->messageHandle, &messageLength); if (messageLength == 0 || messagePayload == NULL) { LogError("Failure from creating Message IoTHubMessage_GetData\r\n"); } else { if (publishMqttMessage(transportState, mqttMsgEntry, messagePayload, messageLength) != 0) { (void)DList_RemoveEntryList(currentListEntry); sendMsgComplete(mqttMsgEntry->iotHubMessageEntry, transportState, IOTHUB_BATCHSTATE_FAILED); free(mqttMsgEntry); } } } } currentListEntry = nextListEntry.Flink; } currentListEntry = transportState->waitingToSend->Flink; /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_027: [IoTHubTransportMqtt_DoWork shall inspect the “waitingToSend” DLIST passed in config structure.] */ while (currentListEntry != transportState->waitingToSend) { IOTHUB_MESSAGE_LIST* iothubMsgList = containingRecord(currentListEntry, IOTHUB_MESSAGE_LIST, entry); DLIST_ENTRY savedFromCurrentListEntry; savedFromCurrentListEntry.Flink = currentListEntry->Flink; /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_027: [IoTHubTransportMqtt_DoWork shall inspect the “waitingToSend” DLIST passed in config structure.] */ size_t messageLength; const unsigned char* messagePayload = RetrieveMessagePayload(iothubMsgList->messageHandle, &messageLength); if (messageLength == 0 || messagePayload == NULL) { LogError("Failure result from IoTHubMessage_GetData\r\n"); } else { /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_029: [IoTHubTransportMqtt_DoWork shall create a MQTT_MESSAGE_HANDLE and pass this to a call to mqtt_client_publish.] */ MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry = (MQTT_MESSAGE_DETAILS_LIST*)malloc(sizeof(MQTT_MESSAGE_DETAILS_LIST)); if (mqttMsgEntry == NULL) { LogError("Allocation Error: Failure allocating MQTT Message Detail List.\r\n"); } else { mqttMsgEntry->retryCount = 0; mqttMsgEntry->msgPacketId = transportState->packetId; mqttMsgEntry->iotHubMessageEntry = iothubMsgList; if (publishMqttMessage(transportState, mqttMsgEntry, messagePayload, messageLength) != 0) { (void)(DList_RemoveEntryList(currentListEntry)); sendMsgComplete(iothubMsgList, transportState, IOTHUB_BATCHSTATE_FAILED); free(mqttMsgEntry); } else { (void)(DList_RemoveEntryList(currentListEntry)); DList_InsertTailList(&(transportState->waitingForAck), &(mqttMsgEntry->entry)); } } } currentListEntry = savedFromCurrentListEntry.Flink; } } /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_030: [IoTHubTransportMqtt_DoWork shall call mqtt_client_dowork everytime it is called if it is connected.] */ mqtt_client_dowork(transportState->mqttClient); } } }
static void MqttOpCompleteCallback(MQTT_CLIENT_HANDLE handle, MQTT_CLIENT_EVENT_RESULT actionResult, const void* msgInfo, void* callbackCtx) { (void)handle; if (callbackCtx != NULL) { PMQTTTRANSPORT_HANDLE_DATA transportData = (PMQTTTRANSPORT_HANDLE_DATA)callbackCtx; switch (actionResult) { case MQTT_CLIENT_ON_PUBLISH_ACK: case MQTT_CLIENT_ON_PUBLISH_COMP: { const PUBLISH_ACK* puback = (const PUBLISH_ACK*)msgInfo; if (puback != NULL) { PDLIST_ENTRY currentListEntry = transportData->waitingForAck.Flink; while (currentListEntry != &transportData->waitingForAck) { MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry = containingRecord(currentListEntry, MQTT_MESSAGE_DETAILS_LIST, entry); DLIST_ENTRY saveListEntry; saveListEntry.Flink = currentListEntry->Flink; if (puback->packetId == mqttMsgEntry->msgPacketId) { (void)DList_RemoveEntryList(currentListEntry); //First remove the item from Waiting for Ack List. sendMsgComplete(mqttMsgEntry->iotHubMessageEntry, transportData, IOTHUB_BATCHSTATE_SUCCESS); free(mqttMsgEntry); } currentListEntry = saveListEntry.Flink; } } break; } case MQTT_CLIENT_ON_CONNACK: { const CONNECT_ACK* connack = (const CONNECT_ACK*)msgInfo; if (connack != NULL) { if (connack->returnCode == CONNECTION_ACCEPTED) { // The connect packet has been acked transportData->currPacketState = CONNACK_TYPE; } else { LogError("Connection not accepted, return code: %d.\r\n", connack->returnCode); (void)mqtt_client_disconnect(transportData->mqttClient); transportData->connected = false; transportData->currPacketState = PACKET_TYPE_ERROR; } } else { LogError("MQTT_CLIENT_ON_CONNACK CONNACK parameter is NULL.\r\n"); } break; } case MQTT_CLIENT_ON_SUBSCRIBE_ACK: { const SUBSCRIBE_ACK* suback = (const SUBSCRIBE_ACK*)msgInfo; if (suback != NULL) { if (suback->qosCount == 1) { // The connect packet has been acked transportData->currPacketState = SUBACK_TYPE; } else { LogError("QOS count was not expected: %d.\r\n", (int)suback->qosCount); } } break; } case MQTT_CLIENT_ON_PUBLISH_RECV: case MQTT_CLIENT_ON_PUBLISH_REL: { // Currently not used break; } case MQTT_CLIENT_ON_DISCONNECT: { // Close the client so we can reconnect again transportData->connected = false; transportData->currPacketState = DISCONNECT_TYPE; break; } case MQTT_CLIENT_ON_ERROR: { xio_close(transportData->xioTransport, NULL, NULL); transportData->connected = false; transportData->currPacketState = PACKET_TYPE_ERROR; } } } }