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; } } } }
void IoTHubClient_LL_SendComplete(IOTHUB_CLIENT_LL_HANDLE handle, PDLIST_ENTRY completed, IOTHUB_BATCHSTATE_RESULT result) { /*Codes_SRS_IOTHUBCLIENT_LL_02_022: [If parameter completed is NULL, or parameter handle is NULL then IoTHubClient_LL_SendBatch shall return.]*/ if ( (handle == NULL) || (completed == NULL) ) { /*"shall return"*/ LogError("invalid arg"); } else { /*Codes_SRS_IOTHUBCLIENT_LL_02_027: [If parameter result is IOTHUB_BACTHSTATE_FAILED then IoTHubClient_LL_SendComplete shall call all the non-NULL callbacks with the result parameter set to IOTHUB_CLIENT_CONFIRMATION_ERROR and the context set to the context passed originally in the SendEventAsync call.] */ /*Codes_SRS_IOTHUBCLIENT_LL_02_025: [If parameter result is IOTHUB_BATCHSTATE_SUCCESS then IoTHubClient_LL_SendComplete shall call all the non-NULL callbacks with the result parameter set to IOTHUB_CLIENT_CONFIRMATION_OK and the context set to the context passed originally in the SendEventAsync call.]*/ IOTHUB_CLIENT_CONFIRMATION_RESULT resultToBeCalled = (result == IOTHUB_BATCHSTATE_SUCCESS) ? IOTHUB_CLIENT_CONFIRMATION_OK : IOTHUB_CLIENT_CONFIRMATION_ERROR; PDLIST_ENTRY oldest; while ((oldest = DList_RemoveHeadList(completed)) != completed) { IOTHUB_MESSAGE_LIST* messageList = (IOTHUB_MESSAGE_LIST*)containingRecord(oldest, IOTHUB_MESSAGE_LIST, entry); /*Codes_SRS_IOTHUBCLIENT_LL_02_026: [If any callback is NULL then there shall not be a callback call.]*/ if (messageList->callback != NULL) { messageList->callback(resultToBeCalled, messageList->context); } IoTHubMessage_Destroy(messageList->messageHandle); free(messageList); } } }
void IoTHubTransportMqtt_Destroy(TRANSPORT_HANDLE handle) { /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_012: [IoTHubTransportMqtt_Destroy shall do nothing if parameter handle is NULL.] */ PMQTTTRANSPORT_HANDLE_DATA transportState = (PMQTTTRANSPORT_HANDLE_DATA)handle; if (transportState != NULL) { transportState->destroyCalled = true; DisconnectFromClient(transportState); //Empty the Waiting for Ack Messages. while (!DList_IsListEmpty(&transportState->waitingForAck)) { PDLIST_ENTRY currentEntry = DList_RemoveHeadList(&transportState->waitingForAck); MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry = containingRecord(currentEntry, MQTT_MESSAGE_DETAILS_LIST, entry); sendMsgComplete(mqttMsgEntry->iotHubMessageEntry, transportState, IOTHUB_BATCHSTATE_FAILED); free(mqttMsgEntry); } /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_014: [IoTHubTransportMqtt_Destroy shall free all the resources currently in use.] */ mqtt_client_deinit(transportState->mqttClient); STRING_delete(transportState->mqttEventTopic); STRING_delete(transportState->mqttMessageTopic); STRING_delete(transportState->device_id); STRING_delete(transportState->device_key); STRING_delete(transportState->sasTokenSr); STRING_delete(transportState->hostAddress); STRING_delete(transportState->configPassedThroughUsername); tickcounter_destroy(g_msgTickCounter); free(transportState); } }
void IoTHubClient_LL_Destroy(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle) { /*Codes_SRS_IOTHUBCLIENT_LL_02_009: [IoTHubClient_LL_Destroy shall do nothing if parameter iotHubClientHandle is NULL.]*/ if (iotHubClientHandle != NULL) { PDLIST_ENTRY unsend; /*Codes_SRS_IOTHUBCLIENT_LL_17_010: [IoTHubClient_LL_Destroy shall call the underlaying layer's _Unregister function] */ IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; handleData->IoTHubTransport_Unregister(handleData->deviceHandle); if (handleData->isSharedTransport == false) { /*Codes_SRS_IOTHUBCLIENT_LL_02_010: [If iotHubClientHandle was not created by IoTHubClient_LL_CreateWithTransport, IoTHubClient_LL_Destroy shall call the underlaying layer's _Destroy function.] */ handleData->IoTHubTransport_Destroy(handleData->transportHandle); } /*if any, remove the items currently not send*/ while ((unsend = DList_RemoveHeadList(&(handleData->waitingToSend))) != &(handleData->waitingToSend)) { IOTHUB_MESSAGE_LIST* temp = containingRecord(unsend, IOTHUB_MESSAGE_LIST, entry); /*Codes_SRS_IOTHUBCLIENT_LL_02_033: [Otherwise, IoTHubClient_LL_Destroy shall complete all the event message callbacks that are in the waitingToSend list with the result IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY.] */ if (temp->callback != NULL) { temp->callback(IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY, temp->context); } IoTHubMessage_Destroy(temp->messageHandle); free(temp); } /*Codes_SRS_IOTHUBCLIENT_LL_17_011: [IoTHubClient_LL_Destroy shall free the resources allocated by IoTHubClient (if any).] */ tickcounter_destroy(handleData->tickCounter); IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle); free(handleData); } }
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; } } } }
void MQTTAPI_DoWork(MQTTAPI_HANDLE instance) { PMQTTTAPI_HANDLE_DATA handle = instance; /* Codes_SRS_MQTTAPI_04_050: [if parameter instance is NULL then MQTTAPI_DoWork shall not perform any action.] */ if (handle != NULL) { if (!checkAndTryToConnect(handle)) { LogError("Client Not Connected and could not connect.\r\n"); } else { if (Lock(handle->LockHandle) == LOCK_OK) { //message { PDLIST_ENTRY received; while ((received = DList_RemoveHeadList(&(handle->messagesReceived))) != &(handle->messagesReceived)) { MQTTAPI_MESSAGE_RECEIVED_LIST* temp = containingRecord(received, MQTTAPI_MESSAGE_RECEIVED_LIST, entry); if (handle->maCallBack != NULL) { if (!handle->maCallBack(handle->maCallbackContext, temp->messageReceived)) { LogError("Client could not handle message, dropping it."); } } free(temp->messageReceived->payload); free(temp->messageReceived); free(temp); } } Unlock(handle->LockHandle); } else { LogError("Could not aquire lock for message.\r\n"); } //Event { PDLIST_ENTRY messageToSend; while ((messageToSend = DList_RemoveHeadList(&(handle->messagesToSend))) != &(handle->messagesToSend)) { MQTTAPI_MESSAGE_SEND_LIST* temp = containingRecord(messageToSend, MQTTAPI_MESSAGE_SEND_LIST, entry); if (MQTTClient_publishMessage(handle->client, STRING_c_str(temp->topicName), temp->messageToSend, &(temp->dt)) != MQTTCLIENT_SUCCESS) { handle->dcCallback(temp->context, MQTTAPI_CONFIRMATION_ERROR); MQTTClient_freeMessage(&(temp->messageToSend)); free(temp->messageToSend); STRING_delete(temp->topicName); free(temp); } else { DList_InsertTailList(&(handle->messagesSent), &(temp->entry)); } } } } } }
void MQTTAPI_Destroy(MQTTAPI_HANDLE instance) { PMQTTTAPI_HANDLE_DATA mqttHandleData = instance; /* Codes_SRS_MQTTAPI_04_021: [If parameter instance is NULL then MQTTAPI_Destroy shall take no action.] */ if (mqttHandleData != NULL) { /* Codes_SRS_MQTTAPI_04_022: [MQTTAPI_Destroy shall free all resources used by MQTTAPI_HANDLE.] */ STRING_delete(mqttHandleData->device_id); STRING_delete(mqttHandleData->device_key); STRING_delete(mqttHandleData->sasTokenSr); /* Codes_SRS_MQTTAPI_04_049: [If the instance is connected, MQTTAPI_Destroy shall disconnect the instance] */ if (mqttHandleData->subscribed) { MQTTAPI_Unsubscribe(mqttHandleData->subscribedTopicHandleData); } if (mqttHandleData->connected) { MQTTClient_disconnect(mqttHandleData->client, 0); } /* Codes_SRS_MQTTAPI_04_053: [If there are messages to be sent MQTTAPI_Destroy shall signalize the user that the message couldn’t be sent by reason of MQTTAPI_CONFIRMATION_BECAUSE_DESTROY] */ { PDLIST_ENTRY received; while ((received = DList_RemoveHeadList(&(mqttHandleData->messagesReceived))) != &(mqttHandleData->messagesReceived)) { MQTTAPI_MESSAGE_RECEIVED_LIST* temp = containingRecord(received, MQTTAPI_MESSAGE_RECEIVED_LIST, entry); if (mqttHandleData->maCallBack != NULL) { if (!mqttHandleData->maCallBack(mqttHandleData->maCallbackContext, temp->messageReceived)) { LogError("Client could not handle message, dropping it."); } } free(temp->messageReceived->payload); free(temp->messageReceived); free(temp); } } { PDLIST_ENTRY messageToSend; while ((messageToSend = DList_RemoveHeadList(&(mqttHandleData->messagesToSend))) != &(mqttHandleData->messagesToSend)) { MQTTAPI_MESSAGE_SEND_LIST* temp = containingRecord(messageToSend, MQTTAPI_MESSAGE_SEND_LIST, entry); if (mqttHandleData->dcCallback != NULL) { mqttHandleData->dcCallback(temp->context, MQTTAPI_CONFIRMATION_BECAUSE_DESTROY); MQTTClient_freeMessage(&(temp->messageToSend)); free(temp->messageToSend); STRING_delete(temp->topicName); free(temp); } } } { PDLIST_ENTRY currentListEntry; while ((currentListEntry = DList_RemoveHeadList(&(mqttHandleData->messagesSent))) != &(mqttHandleData->messagesSent)) { MQTTAPI_MESSAGE_SEND_LIST* temp = containingRecord(currentListEntry, MQTTAPI_MESSAGE_SEND_LIST, entry); if (mqttHandleData->dcCallback != NULL) { mqttHandleData->dcCallback(temp->context, MQTTAPI_CONFIRMATION_BECAUSE_DESTROY); MQTTClient_freeMessage(&(temp->messageToSend)); free(temp->messageToSend); STRING_delete(temp->topicName); free(temp); } } } MQTTClient_destroy(mqttHandleData->client); Lock_Deinit(mqttHandleData->LockHandle); free(mqttHandleData); } }