int prov_transport_common_mqtt_close(PROV_DEVICE_TRANSPORT_HANDLE handle) { int result; if (handle == NULL) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_011: [ If handle is NULL, prov_transport_common_mqtt_close shall return a non-zero value. ] */ LogError("Invalid parameter specified handle: %p", handle); result = __FAILURE__; } else { PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle; BUFFER_delete(mqtt_info->ek); mqtt_info->ek = NULL; BUFFER_delete(mqtt_info->srk); mqtt_info->srk = NULL; free(mqtt_info->registration_id); mqtt_info->registration_id = NULL; /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_012: [ prov_transport_common_mqtt_close shall close all connection associated with mqtt communication. ] */ if (mqtt_client_disconnect(mqtt_info->mqtt_client, NULL, NULL) == 0) { mqtt_client_dowork(mqtt_info->mqtt_client); } xio_destroy(mqtt_info->transport_io); mqtt_info->transport_io = NULL; /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_013: [ On success prov_transport_common_mqtt_close shall return a zero value. ] */ mqtt_info->mqtt_state = MQTT_STATE_IDLE; result = 0; } return result; }
void mqtt_client_sample_run() { if (platform_init() != 0) { PrintLogFunction(LOG_LINE, "platform_init failed"); } else { MQTT_CLIENT_HANDLE mqttHandle = mqtt_client_init(OnRecvCallback, OnOperationComplete, NULL, PrintLogFunction); if (mqttHandle == NULL) { PrintLogFunction(LOG_LINE, "mqtt_client_init failed"); } else { MQTT_CLIENT_OPTIONS options = { 0 }; options.clientId = "azureiotclient"; options.willMessage = NULL; options.username = NULL; options.password = NULL; options.keepAliveInterval = 10; options.useCleanSession = true; options.qualityOfServiceValue = DELIVER_AT_MOST_ONCE; SOCKETIO_CONFIG config = {"test.mosquitto.org", PORT_NUM_UNENCRYPTED, NULL}; XIO_HANDLE xio = xio_create(socketio_get_interface_description(), &config, PrintLogFunction); if (xio == NULL) { PrintLogFunction(LOG_LINE, "xio_create failed"); } else { if (mqtt_client_connect(mqttHandle, xio, &options) != 0) { PrintLogFunction(LOG_LINE, "mqtt_client_connect failed"); } else { do { mqtt_client_dowork(mqttHandle); } while (g_continue); } xio_close(xio, OnCloseComplete, NULL); } mqtt_client_deinit(mqttHandle); } platform_deinit(); } #ifdef _CRT_DBG_MAP_ALLOC _CrtDumpMemoryLeaks(); #endif }
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); } } }
void prov_transport_common_mqtt_dowork(PROV_DEVICE_TRANSPORT_HANDLE handle) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_046: [ If handle is NULL, prov_transport_common_mqtt_dowork shall do nothing. ] */ if (handle != NULL) { PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle; if (mqtt_info->mqtt_state == MQTT_STATE_DISCONNECTED) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_047: [ If the mqtt_state is MQTT_STATE_DISCONNECTED prov_transport_common_mqtt_dowork shall attempt to connect the mqtt connections. ] */ if (create_connection(mqtt_info) != 0) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */ LogError("unable to create amqp connection"); mqtt_info->mqtt_state = MQTT_STATE_ERROR; mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR; } else { mqtt_info->mqtt_state = MQTT_STATE_CONNECTING; } } else if (mqtt_info->mqtt_state == MQTT_STATE_CONNECTED) { mqtt_client_dowork(mqtt_info->mqtt_client); /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_050: [ When the mqtt_state is MQTT_STATE_CONNECTED, prov_transport_common_mqtt_dowork shall subscribe to the topic $dps/registrations/res/# ] */ if (subscribe_to_topic(mqtt_info) != 0) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */ LogError("Failure subscribing to topic"); mqtt_info->mqtt_state = MQTT_STATE_ERROR; mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR; } else { mqtt_info->status_cb(PROV_DEVICE_TRANSPORT_STATUS_CONNECTED, mqtt_info->status_ctx); mqtt_info->mqtt_state = MQTT_STATE_SUBSCRIBING; } } else if (mqtt_info->mqtt_state != MQTT_STATE_IDLE) { mqtt_client_dowork(mqtt_info->mqtt_client); if (mqtt_info->mqtt_state == MQTT_STATE_SUBSCRIBED || mqtt_info->mqtt_state == MQTT_STATE_ERROR) { switch (mqtt_info->transport_state) { case TRANSPORT_CLIENT_STATE_REG_SEND: /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_053: [ When then transport_state is set to TRANSPORT_CLIENT_STATE_REG_SEND, prov_transport_common_mqtt_dowork shall send a REGISTER_ME message ] */ if (send_register_message(mqtt_info) != 0) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */ mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR; mqtt_info->mqtt_state = MQTT_STATE_ERROR; } else { /* Codes_PROV_TRANSPORT_AMQP_COMMON_07_054: [ Upon successful sending of a TRANSPORT_CLIENT_STATE_REG_SEND message, prov_transport_common_mqtt_dowork shall set the transport_state to TRANSPORT_CLIENT_STATE_REG_SENT ] */ mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_REG_SENT; } break; case TRANSPORT_CLIENT_STATE_STATUS_SEND: /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_055: [ When then transport_state is set to TRANSPORT_CLIENT_STATE_STATUS_SEND, prov_transport_common_mqtt_dowork shall send a AMQP_OPERATION_STATUS message ] */ if (send_operation_status_message(mqtt_info) != 0) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */ mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR; mqtt_info->mqtt_state = MQTT_STATE_ERROR; } else { /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_056: [ Upon successful sending of a AMQP_OPERATION_STATUS message, prov_transport_common_mqtt_dowork shall set the transport_state to TRANSPORT_CLIENT_STATE_STATUS_SENT ] */ mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_STATUS_SENT; } break; case TRANSPORT_CLIENT_STATE_REG_RECV: case TRANSPORT_CLIENT_STATE_STATUS_RECV: { PROV_JSON_INFO* parse_info = mqtt_info->json_parse_cb(mqtt_info->payload_data, mqtt_info->json_ctx); if (parse_info == NULL) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */ LogError("Unable to process registration reply."); mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR; mqtt_info->mqtt_state = MQTT_STATE_ERROR; } else { switch (parse_info->prov_status) { case PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED: case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNING: if (parse_info->operation_id == NULL) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */ LogError("Failure operation Id invalid"); mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR; mqtt_info->mqtt_state = MQTT_STATE_ERROR; } else if (mqtt_info->operation_id == NULL && mallocAndStrcpy_s(&mqtt_info->operation_id, parse_info->operation_id) != 0) { /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */ LogError("Failure copying operation Id"); mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR; mqtt_info->mqtt_state = MQTT_STATE_ERROR; } else { if (mqtt_info->status_cb != NULL) { mqtt_info->status_cb(parse_info->prov_status, mqtt_info->status_ctx); } mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE; } break; case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNED: mqtt_info->register_data_cb(PROV_DEVICE_TRANSPORT_RESULT_OK, parse_info->authorization_key, parse_info->iothub_uri, parse_info->device_id, mqtt_info->user_ctx); mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE; break; case PROV_DEVICE_TRANSPORT_STATUS_ERROR: default: /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */ LogError("Unable to process message reply."); mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR; mqtt_info->mqtt_state = MQTT_STATE_ERROR; break; } free_json_parse_info(parse_info); } break; } case TRANSPORT_CLIENT_STATE_ERROR: /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_057: [ If transport_state is set to TRANSPORT_CLIENT_STATE_ERROR, prov_transport_common_mqtt_dowork shall call the register_data_cb function with PROV_DEVICE_TRANSPORT_RESULT_ERROR setting the transport_state to TRANSPORT_CLIENT_STATE_IDLE ] */ mqtt_info->register_data_cb(PROV_DEVICE_TRANSPORT_RESULT_ERROR, NULL, NULL, NULL, mqtt_info->user_ctx); mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE; mqtt_info->mqtt_state = MQTT_STATE_IDLE; break; case TRANSPORT_CLIENT_STATE_REG_SENT: case TRANSPORT_CLIENT_STATE_STATUS_SENT: break; case TRANSPORT_CLIENT_STATE_IDLE: default: break; } } } } }