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; } } } }
/*returns 0 on success, any other value is error*/ static int attach_ms_timesOutAfter(IOTHUB_CLIENT_LL_HANDLE_DATA* handleData, IOTHUB_MESSAGE_LIST *newEntry) { int result; /*Codes_SRS_IOTHUBCLIENT_LL_02_043: [ Calling IoTHubClient_LL_SetOption with value set to "0" shall disable the timeout mechanism for all new messages. ]*/ if (handleData->currentMessageTimeout == 0) { newEntry->ms_timesOutAfter = 0; /*do not timeout*/ result = 0; } else { /*Codes_SRS_IOTHUBCLIENT_LL_02_039: [ "messageTimeout" - once IoTHubClient_LL_SendEventAsync is called the message shall timeout after value miliseconds. Value is a pointer to a uint64. ]*/ if (tickcounter_get_current_ms(handleData->tickCounter, &newEntry->ms_timesOutAfter) != 0) { result = __LINE__; LogError("unable to get the current relative tickcount"); } else { newEntry->ms_timesOutAfter += handleData->currentMessageTimeout; result = 0; } } return result; }
static int publishMqttMessage(PMQTTTRANSPORT_HANDLE_DATA transportState, MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry, const unsigned char* payload, size_t len) { int result; MQTT_MESSAGE_HANDLE mqttMsg = mqttmessage_create(transportState->packetId++, STRING_c_str(transportState->mqttEventTopic), DELIVER_AT_LEAST_ONCE, payload, len); if (mqttMsg == NULL) { result = __LINE__; } else { if (mqtt_client_publish(transportState->mqttClient, mqttMsg) != 0) { result = __LINE__; } else { mqttMsgEntry->retryCount++; (void)tickcounter_get_current_ms(g_msgTickCounter, &mqttMsgEntry->msgPublishTime); result = 0; } mqttmessage_destroy(mqttMsg); } return result; }
int main(int argc, char** argv) { int result; (void)argc; (void)argv; if (platform_init() != 0) { result = -1; } else { XIO_HANDLE sasl_io; CONNECTION_HANDLE connection; SESSION_HANDLE session; LINK_HANDLE link; MESSAGE_SENDER_HANDLE message_sender; MESSAGE_HANDLE message; SASL_PLAIN_CONFIG sasl_plain_config = { EH_KEY_NAME, EH_KEY, NULL }; TLSIO_CONFIG tls_io_config = { EH_HOST, 5671 }; const IO_INTERFACE_DESCRIPTION* tlsio_interface; SASLCLIENTIO_CONFIG sasl_io_config; AMQP_VALUE source; AMQP_VALUE target; size_t last_memory_used = 0; SASL_MECHANISM_HANDLE sasl_mechanism_handle; XIO_HANDLE tls_io; unsigned char hello[] = { 'H', 'e', 'l', 'l', 'o' }; BINARY_DATA binary_data; gballoc_init(); /* create SASL PLAIN handler */ sasl_mechanism_handle = saslmechanism_create(saslplain_get_interface(), &sasl_plain_config); /* create the TLS IO */ tlsio_interface = platform_get_default_tlsio(); tls_io = xio_create(tlsio_interface, &tls_io_config); /* create the SASL client IO using the TLS IO */ sasl_io_config.underlying_io = tls_io; sasl_io_config.sasl_mechanism = sasl_mechanism_handle; sasl_io = xio_create(saslclientio_get_interface_description(), &sasl_io_config); /* create the connection, session and link */ connection = connection_create(sasl_io, EH_HOST, "some", NULL, NULL); session = session_create(connection, NULL, NULL); session_set_incoming_window(session, 2147483647); session_set_outgoing_window(session, 65536); source = messaging_create_source("ingress"); target = messaging_create_target("amqps://" EH_HOST "/" EH_NAME); link = link_create(session, "sender-link", role_sender, source, target); link_set_snd_settle_mode(link, sender_settle_mode_unsettled); (void)link_set_max_message_size(link, 65536); amqpvalue_destroy(source); amqpvalue_destroy(target); message = message_create(); binary_data.bytes = hello; binary_data.length = sizeof(hello); message_add_body_amqp_data(message, binary_data); /* create a message sender */ message_sender = messagesender_create(link, NULL, NULL); if (messagesender_open(message_sender) == 0) { uint32_t i; bool keep_running = true; tickcounter_ms_t start_time; TICK_COUNTER_HANDLE tick_counter = tickcounter_create(); if (tickcounter_get_current_ms(tick_counter, &start_time) != 0) { (void)printf("Error getting start time\r\n"); } else { for (i = 0; i < msg_count; i++) { (void)messagesender_send(message_sender, message, on_message_send_complete, message); } message_destroy(message); while (keep_running) { size_t current_memory_used; size_t maximum_memory_used; connection_dowork(connection); current_memory_used = gballoc_getCurrentMemoryUsed(); maximum_memory_used = gballoc_getMaximumMemoryUsed(); if (current_memory_used != last_memory_used) { (void)printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used); last_memory_used = current_memory_used; } if (sent_messages == msg_count) { break; } } { tickcounter_ms_t end_time; if (tickcounter_get_current_ms(tick_counter, &end_time) != 0) { (void)printf("Error getting end time\r\n"); } else { (void)printf("Send %u messages in %lu ms: %.02f msgs/sec\r\n", (unsigned int)msg_count, (unsigned long)(end_time - start_time), (float)msg_count / ((float)(end_time - start_time) / 1000)); } } } } else { message_destroy(message); } messagesender_destroy(message_sender); link_destroy(link); session_destroy(session); connection_destroy(connection); xio_destroy(sasl_io); xio_destroy(tls_io); saslmechanism_destroy(sasl_mechanism_handle); platform_deinit(); (void)printf("Max memory usage:%lu\r\n", (unsigned long)gballoc_getCurrentMemoryUsed()); (void)printf("Current memory usage:%lu\r\n", (unsigned long)gballoc_getMaximumMemoryUsed()); gballoc_deinit(); result = 0; } return result; }
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); } } }
int main(int argc, char** argv) { int result; (void)argc; (void)argv; if (platform_init() != 0) { result = -1; } else { XIO_HANDLE sasl_io; CONNECTION_HANDLE connection; SESSION_HANDLE session; LINK_HANDLE link; MESSAGE_SENDER_HANDLE message_sender; MESSAGE_HANDLE message; size_t last_memory_used = 0; /* create SASL PLAIN handler */ SASL_MECHANISM_HANDLE sasl_mechanism_handle = saslmechanism_create(saslmssbcbs_get_interface(), NULL); XIO_HANDLE tls_io; STRING_HANDLE sas_key_name; STRING_HANDLE sas_key_value; STRING_HANDLE resource_uri; STRING_HANDLE encoded_resource_uri; STRING_HANDLE sas_token; BUFFER_HANDLE buffer; TLSIO_CONFIG tls_io_config = { EH_HOST, 5671 }; const IO_INTERFACE_DESCRIPTION* tlsio_interface; SASLCLIENTIO_CONFIG sasl_io_config; time_t currentTime; size_t expiry_time; CBS_HANDLE cbs; AMQP_VALUE source; AMQP_VALUE target; unsigned char hello[] = { 'H', 'e', 'l', 'l', 'o' }; BINARY_DATA binary_data; gballoc_init(); /* create the TLS IO */ tlsio_interface = platform_get_default_tlsio(); tls_io = xio_create(tlsio_interface, &tls_io_config); /* create the SASL client IO using the TLS IO */ sasl_io_config.underlying_io = tls_io; sasl_io_config.sasl_mechanism = sasl_mechanism_handle; sasl_io = xio_create(saslclientio_get_interface_description(), &sasl_io_config); /* create the connection, session and link */ connection = connection_create(sasl_io, EH_HOST, "some", NULL, NULL); session = session_create(connection, NULL, NULL); session_set_incoming_window(session, 2147483647); session_set_outgoing_window(session, 65536); /* Construct a SAS token */ sas_key_name = STRING_construct(EH_KEY_NAME); /* unfortunately SASToken wants an encoded key - this should be fixed at a later time */ buffer = BUFFER_create((unsigned char*)EH_KEY, strlen(EH_KEY)); sas_key_value = Base64_Encoder(buffer); BUFFER_delete(buffer); resource_uri = STRING_construct("sb://" EH_HOST "/" EH_NAME "/publishers/" EH_PUBLISHER); encoded_resource_uri = URL_EncodeString(STRING_c_str(resource_uri)); /* Make a token that expires in one hour */ currentTime = time(NULL); expiry_time = (size_t)(difftime(currentTime, 0) + 3600); sas_token = SASToken_Create(sas_key_value, encoded_resource_uri, sas_key_name, expiry_time); cbs = cbs_create(session); if (cbs_open_async(cbs, on_cbs_open_complete, cbs, on_cbs_error, cbs) == 0) { (void)cbs_put_token_async(cbs, "servicebus.windows.net:sastoken", "sb://" EH_HOST "/" EH_NAME "/publishers/" EH_PUBLISHER, STRING_c_str(sas_token), on_cbs_put_token_complete, cbs); while (!auth) { size_t current_memory_used; size_t maximum_memory_used; connection_dowork(connection); current_memory_used = gballoc_getCurrentMemoryUsed(); maximum_memory_used = gballoc_getMaximumMemoryUsed(); if (current_memory_used != last_memory_used) { (void)printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used); last_memory_used = current_memory_used; } } } STRING_delete(sas_token); STRING_delete(sas_key_name); STRING_delete(sas_key_value); STRING_delete(resource_uri); STRING_delete(encoded_resource_uri); source = messaging_create_source("ingress"); target = messaging_create_target("amqps://" EH_HOST "/" EH_NAME); link = link_create(session, "sender-link", role_sender, source, target); link_set_snd_settle_mode(link, sender_settle_mode_settled); (void)link_set_max_message_size(link, 65536); amqpvalue_destroy(source); amqpvalue_destroy(target); message = message_create(); binary_data.bytes = hello; binary_data.length = sizeof(hello); message_add_body_amqp_data(message, binary_data); /* create a message sender */ message_sender = messagesender_create(link, NULL, NULL); if (messagesender_open(message_sender) == 0) { uint32_t i; bool keep_running = true; tickcounter_ms_t start_time; TICK_COUNTER_HANDLE tick_counter = tickcounter_create(); if (tickcounter_get_current_ms(tick_counter, &start_time) != 0) { (void)printf("Error getting start time\r\n"); } else { for (i = 0; i < msg_count; i++) { (void)messagesender_send(message_sender, message, on_message_send_complete, message); } message_destroy(message); while (keep_running) { size_t current_memory_used; size_t maximum_memory_used; connection_dowork(connection); current_memory_used = gballoc_getCurrentMemoryUsed(); maximum_memory_used = gballoc_getMaximumMemoryUsed(); if (current_memory_used != last_memory_used) { (void)printf("Current memory usage:%lu (max:%lu)\r\n", (unsigned long)current_memory_used, (unsigned long)maximum_memory_used); last_memory_used = current_memory_used; } if (sent_messages == msg_count) { break; } } { tickcounter_ms_t end_time; if (tickcounter_get_current_ms(tick_counter, &end_time) != 0) { (void)printf("Error getting end time\r\n"); } else { (void)printf("Send %u messages in %lu ms: %.02f msgs/sec\r\n", (unsigned int)msg_count, (unsigned long)(end_time - start_time), (float)msg_count / ((float)(end_time - start_time) / 1000)); } } } } messagesender_destroy(message_sender); link_destroy(link); session_destroy(session); connection_destroy(connection); xio_destroy(sasl_io); xio_destroy(tls_io); saslmechanism_destroy(sasl_mechanism_handle); platform_deinit(); (void)printf("Max memory usage:%lu\r\n", (unsigned long)gballoc_getCurrentMemoryUsed()); (void)printf("Current memory usage:%lu\r\n", (unsigned long)gballoc_getMaximumMemoryUsed()); gballoc_deinit(); result = 0; } return result; }