static void setup_dev_auth_emulator_generate_credentials_mocks(const char* token_scope) { STRICT_EXPECTED_CALL(STRING_new()); STRICT_EXPECTED_CALL(get_time(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(STRING_construct(token_scope)); STRICT_EXPECTED_CALL(STRING_construct(IGNORED_PTR_ARG)) .IgnoreArgument_psz(); STRICT_EXPECTED_CALL(SASToken_Create(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_NUM_ARG)) .IgnoreArgument_scope() .IgnoreArgument_keyName() .IgnoreArgument_expiry() .IgnoreArgument_key(); STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); STRICT_EXPECTED_CALL(mallocAndStrcpy_s(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_destination() .IgnoreArgument_source(); STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); }
static int InitializeConnection(PMQTTTRANSPORT_HANDLE_DATA transportState, bool initialConnection) { int result = 0; if (!transportState->connected && !transportState->destroyCalled) { // Construct SAS token size_t secSinceEpoch = (size_t)(difftime(get_time(NULL), EPOCH_TIME_T_VALUE) + 0); size_t expiryTime = secSinceEpoch + SAS_TOKEN_DEFAULT_LIFETIME; // Not checking the success of this variable, if fail it will fail in the SASToken creation and return false; STRING_HANDLE emptyKeyName = STRING_new(); STRING_HANDLE sasToken = SASToken_Create(transportState->device_key, transportState->sasTokenSr, emptyKeyName, expiryTime); if (sasToken == NULL) { result = __LINE__; } else { MQTT_CLIENT_OPTIONS options = { 0 }; options.clientId = (char*)STRING_c_str(transportState->device_id); options.willMessage = NULL; options.username = (char*)STRING_c_str(transportState->configPassedThroughUsername); options.password = (char*)STRING_c_str(sasToken); options.keepAliveInterval = DEFAULT_MQTT_KEEPALIVE; options.useCleanSession = false; options.qualityOfServiceValue = DELIVER_AT_LEAST_ONCE; // construct address const char* hostAddress = STRING_c_str(transportState->hostAddress); const char* hostName = strstr(hostAddress, "//"); if (hostName == NULL) { hostName = hostAddress; } else { // Increment beyond the double backslash hostName += 2; } transportState->xioTransport = getIoTransportProvider(hostName, transportState->portNum); if (mqtt_client_connect(transportState->mqttClient, transportState->xioTransport, &options) != 0) { LogError("failure connecting to address %s:%d.\r\n", STRING_c_str(transportState->hostAddress), transportState->portNum); result = __LINE__; } else { transportState->connected = true; result = 0; } STRING_delete(emptyKeyName); STRING_delete(sasToken); } } return result; }
const char* IoTHubAccount_GetSharedAccessSignature(IOTHUB_ACCOUNT_INFO_HANDLE acctHandle) { const char* result = NULL; IOTHUB_ACCOUNT_INFO* acctInfo = (IOTHUB_ACCOUNT_INFO*)acctHandle; if (acctInfo != NULL) { if (acctInfo->sharedAccessToken != NULL) { // Reuse the sharedAccessToken if it's been created already result = acctInfo->sharedAccessToken; } else { time_t currentTime = time(NULL); size_t expiry_time = (size_t)(currentTime + 3600); STRING_HANDLE accessKey = STRING_construct(acctInfo->sharedAccessKey); STRING_HANDLE iotName = STRING_construct(acctInfo->hostname); STRING_HANDLE keyName = STRING_construct(acctInfo->keyName); if (accessKey != NULL && iotName != NULL && keyName != NULL) { STRING_HANDLE sasHandle = SASToken_Create(accessKey, iotName, keyName, expiry_time); if (sasHandle == NULL) { result = NULL; } else { if (mallocAndStrcpy_s(&acctInfo->sharedAccessToken, STRING_c_str(sasHandle)) != 0) { result = NULL; } else { result = acctInfo->sharedAccessToken; } STRING_delete(sasHandle); } } STRING_delete(accessKey); STRING_delete(iotName); STRING_delete(keyName); } } else { result = NULL; } return result; }
HTTPAPIEX_RESULT HTTPAPIEX_SAS_ExecuteRequest(HTTPAPIEX_SAS_HANDLE sasHandle, HTTPAPIEX_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode, HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent) { /*Codes_SRS_HTTPAPIEXSAS_06_007: [If the parameter sasHandle is NULL then HTTPAPIEX_SAS_ExecuteRequest shall simply invoke HTTPAPIEX_ExecuteRequest with the remaining parameters (following sasHandle) as its arguments and shall return immediately with the result of that call as the result of HTTPAPIEX_SAS_ExecuteRequest.]*/ if (sasHandle != NULL) { /*Codes_SRS_HTTPAPIEXSAS_06_008: [if the parameter requestHttpHeadersHandle is NULL then fallthrough.]*/ if (requestHttpHeadersHandle != NULL) { /*Codes_SRS_HTTPAPIEXSAS_06_009: [HTTPHeaders_FindHeaderValue shall be invoked with the requestHttpHeadersHandle as its first argument and the string "Authorization" as its second argument.]*/ /*Codes_SRS_HTTPAPIEXSAS_06_010: [If the return result of the invocation of HTTPHeaders_FindHeaderValue is NULL then fallthrough.]*/ if (HTTPHeaders_FindHeaderValue(requestHttpHeadersHandle, "Authorization") != NULL) { HTTPAPIEX_SAS_STATE* state = (HTTPAPIEX_SAS_STATE*)sasHandle; /*Codes_SRS_HTTPAPIEXSAS_06_018: [A value of type time_t that shall be known as currentTime is obtained from calling get_time.]*/ time_t currentTime = get_time(NULL); /*Codes_SRS_HTTPAPIEXSAS_06_019: [If the value of currentTime is (time_t)-1 is then fallthrough.]*/ if (currentTime == (time_t)-1) { LogError("Time does not appear to be working.\r\n"); } else { /*Codes_SRS_HTTPAPIEXSAS_06_011: [SASToken_Create shall be invoked.]*/ /*Codes_SRS_HTTPAPIEXSAS_06_012: [If the return result of SASToken_Create is NULL then fallthrough.]*/ size_t expiry = (size_t)(difftime(currentTime, 0) + 3600); STRING_HANDLE newSASToken = SASToken_Create(state->key, state->uriResource, state->keyName, expiry); if (newSASToken != NULL) { /*Codes_SRS_HTTPAPIEXSAS_06_013: [HTTPHeaders_ReplaceHeaderNameValuePair shall be invoked with "Authorization" as its second argument and STRING_c_str (newSASToken) as its third argument.]*/ if (HTTPHeaders_ReplaceHeaderNameValuePair(requestHttpHeadersHandle, "Authorization", STRING_c_str(newSASToken)) != HTTP_HEADERS_OK) { /*Codes_SRS_HTTPAPIEXSAS_06_014: [If the result of the invocation of HTTPHeaders_ReplaceHeaderNameValuePair is NOT HTTP_HEADERS_OK then fallthrough.]*/ LogError("Unable to replace the old SAS Token.\r\n"); } /*Codes_SRS_HTTPAPIEXSAS_06_015: [STRING_delete(newSASToken) will be invoked.]*/ STRING_delete(newSASToken); } else { LogError("Unable to create a new SAS token.\r\n"); } } } } } /*Codes_SRS_HTTPAPIEXSAS_06_016: [HTTPAPIEX_ExecuteRequest with the remaining parameters (following sasHandle) as its arguments will be invoked and the result of that call is the result of HTTPAPIEX_SAS_ExecuteRequest.]*/ return HTTPAPIEX_ExecuteRequest(handle,requestType,relativePath,requestHttpHeadersHandle,requestContent,statusCode,responseHeadersHandle,responseContent); }
static bool checkAndTryToConnect(PMQTTTAPI_HANDLE_DATA mqttApiState) { bool result; if (mqttApiState != NULL) { if (!mqttApiState->connected) { /* Codes_SRS_MQTTAPI_04_062: [MQTTAPI_create shall generate SAS Token with an expiring time of 1 hour.] */ size_t secondsSinceEpoch = (size_t)(difftime(get_time(NULL), EPOCH_TIME_T_VALUE) + 0); size_t possibleNewExpiry = secondsSinceEpoch + mqttApiState->sasTokenLifetime; STRING_HANDLE zeroLengthString; if ((zeroLengthString = STRING_new()) == NULL) { LogError("Could not generate zeroLenghtString for skn. \r\n"); result = false; } else { STRING_HANDLE newSASToken = SASToken_Create(mqttApiState->device_key, mqttApiState->sasTokenSr, zeroLengthString, possibleNewExpiry); if (newSASToken == NULL) { LogError("Could not generate a SAS Token\r\n"); result = false; } else { /* Codes_SRS_MQTTAPI_04_024: [MQTTAPI_Create shall call underlying library connection functions to establish connection with the server.] */ if (!connectToMQTTServer(mqttApiState->client, STRING_c_str(mqttApiState->device_id), STRING_c_str(newSASToken))) { /* Tests_SRS_MQTTAPI_04_025: [If connection fails MQTTAPI_Create shall return NULL. */ result = false; } else { mqttApiState->connected = true; mqttApiState->lastExpiryUsed = possibleNewExpiry; result = true; } STRING_delete(newSASToken); } STRING_delete(zeroLengthString); } } else { //Here is the point that we need to check if we need to disconnect, generate a new SAS Token and Connect Again. size_t secondsSinceEpoch; int differenceWithLastExpiry; secondsSinceEpoch = (size_t)(difftime(get_time(NULL), EPOCH_TIME_T_VALUE) + 0); differenceWithLastExpiry = mqttApiState->lastExpiryUsed - secondsSinceEpoch; /* Codes_SRS_MQTTAPI_04_063: [DoWork shall check the SAS Token Expiration time for the current connection. If the token is near to expire and there is no pending item, it shall disconnect, generate a new SAS Token with 1 hour expiration and connect again.] */ if ((differenceWithLastExpiry <= 0) || (((size_t)differenceWithLastExpiry) < mqttApiState->sasRefreshLine && DList_IsListEmpty(&(mqttApiState->messagesSent)) ) ) // Within refresh minutes (or past if negative) of the expiration { /* First Disconnect */ /* Codes_SRS_MQTTAPI_04_064: [If the token is expired we shall disconnect, signal that all pending message are failed due to Token Expired.] */ if (MQTTClient_disconnect(mqttApiState->client, 0) != MQTTCLIENT_SUCCESS) { LogError("Token is Expired or about to be expired and Disconnect Failed. \r\n"); } else { size_t possibleNewExpiry = secondsSinceEpoch + mqttApiState->sasTokenLifetime; STRING_HANDLE zeroLengthString; if ((zeroLengthString = STRING_new()) == NULL) { LogError("Could not generate zeroLenghtString for skn. \r\n"); result = false; } else { STRING_HANDLE newSASToken = SASToken_Create(mqttApiState->device_key, mqttApiState->sasTokenSr, zeroLengthString, possibleNewExpiry); mqttApiState->connected = false; if (newSASToken == NULL) { LogError("Could not generate a SAS Token\r\n"); result = false; } else { /* Codes_SRS_MQTTAPI_04_024: [MQTTAPI_Create shall call underlying library connection functions to establish connection with the server.] */ if (!connectToMQTTServer(mqttApiState->client, STRING_c_str(mqttApiState->device_id), STRING_c_str(newSASToken))) { /* Tests_SRS_MQTTAPI_04_025: [If connection fails MQTTAPI_Create shall return NULL. */ result = false; } else { mqttApiState->connected = true; mqttApiState->lastExpiryUsed = possibleNewExpiry; if (mqttApiState->subscribed) { int rc; LogInfo("Trying to Subscribe after reconnect.\r\n"); if ((rc = MQTTClient_subscribe(mqttApiState->client, STRING_c_str(mqttApiState->subscribedTopicHandleData->topicName), SUBSCRIBEQOS)) != MQTTCLIENT_SUCCESS) { LogError("Could not subscribe again. Won't be able to receive messages. Error Code: %d.\r\n", rc); } else { LogInfo("Subscribed succesfully after reconnect..\r\n"); } } result = true; } STRING_delete(newSASToken); } STRING_delete(zeroLengthString); } } } result = true; } } else { LogError("Invalid Arg. Handle is NULL. \r\n"); result = false; } 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; 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; }