Microsoft Azure IoTHub client AMQP transport

Dependents:   sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp iothub_client_sample_amqp ... more

This library implements the AMQP transport for Microsoft Azure IoTHub client. The code is replicated from https://github.com/Azure/azure-iot-sdks

Revision:
22:8b70cf813f25
Parent:
21:32a1746384ba
Child:
23:2c6779675a01
--- a/iothubtransportamqp.c	Fri Aug 12 10:03:28 2016 -0700
+++ b/iothubtransportamqp.c	Fri Aug 26 12:58:26 2016 -0700
@@ -34,6 +34,8 @@
 #include "iothubtransportamqp.h"
 #include "iothub_client_version.h"
 
+#define INDEFINITE_TIME ((time_t)(-1))
+
 #define RESULT_OK 0
 #define RESULT_FAILURE 1
 #define RESULT_TIMEOUT 2
@@ -207,9 +209,24 @@
     return result;
 }
 
-static size_t getSecondsSinceEpoch(void)
+static int getSecondsSinceEpoch(size_t* seconds)
 {
-    return (size_t)(difftime(get_time(NULL), (time_t)0));
+	int result;
+	time_t current_time;
+	
+	if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
+	{
+		LogError("Failed getting the current local time (get_time() failed)");
+		result = __LINE__;
+	}
+	else
+	{
+		*seconds = (size_t)get_difftime(current_time, (time_t)0);
+		
+		result = RESULT_OK;
+	}
+	
+	return result;
 }
 
 static void trackEventInProgress(IOTHUB_MESSAGE_LIST* message, AMQP_TRANSPORT_INSTANCE* transport_state)
@@ -661,6 +678,11 @@
 
 static void on_put_token_complete(void* context, CBS_OPERATION_RESULT operation_result, unsigned int status_code, const char* status_description)
 {
+#ifdef NO_LOGGING
+    UNUSED(status_code);
+    UNUSED(status_description);
+#endif
+
     AMQP_TRANSPORT_INSTANCE* transportState = (AMQP_TRANSPORT_INSTANCE*)context;
 
     if (operation_result == CBS_OPERATION_RESULT_OK)
@@ -935,9 +957,13 @@
                             result = RESULT_FAILURE;
                             LogError("Failed to open the connection with CBS.");
                         }
+						else if (getSecondsSinceEpoch(&transport_state->connection_establish_time) != RESULT_OK)
+						{
+							LogError("Failed setting the connection establish time.");
+							result = RESULT_FAILURE;
+						}
                         else
                         {
-                            transport_state->connection_establish_time = getSecondsSinceEpoch();
                             transport_state->cbs.cbs_state = CBS_STATE_IDLE;
                             connection_set_trace(transport_state->connection, transport_state->is_trace_on);
                             (void)xio_setoption(transport_state->cbs.sasl_io, OPTION_LOG_TRACE, &transport_state->is_trace_on);
@@ -980,10 +1006,17 @@
                             LogError("Failed to set the AMQP outgoing window size.");
                         }
 
-                        transport_state->connection_establish_time = getSecondsSinceEpoch();
+						if (getSecondsSinceEpoch(&transport_state->connection_establish_time) != RESULT_OK)
+						{
+							LogError("Failed setting the connection establish time.");
+							result = RESULT_FAILURE;
+						}
+						else
+						{
                         connection_set_trace(transport_state->connection, transport_state->is_trace_on);
                         (void)xio_setoption(transport_state->tls_io, OPTION_LOG_TRACE, &transport_state->is_trace_on);
                         result = RESULT_OK;
+						}
                     }
                 }
                 break;
@@ -1025,79 +1058,97 @@
 static int startAuthentication(AMQP_TRANSPORT_INSTANCE* transport_state)
 {
     int result;
-
-    size_t sas_token_create_time = getSecondsSinceEpoch(); // I.e.: NOW, in seconds since epoch.
+    size_t currentTimeInSeconds;
 
-                                                           // Codes_SRS_IOTHUBTRANSPORTAMQP_09_083: [Each new SAS token created by the transport shall be valid for up to 'sas_token_lifetime' milliseconds from the time of creation]
-    size_t new_expiry_time = sas_token_create_time + (transport_state->cbs.sas_token_lifetime / 1000);
+	if (getSecondsSinceEpoch(&currentTimeInSeconds) != RESULT_OK)
+	{
+		LogError("Failed getting current time to compute the SAS token creation time.");
+		result = __LINE__;
+	}
+	else
+	{
+		// Codes_SRS_IOTHUBTRANSPORTAMQP_09_083: [SAS tokens expiration time shall be calculated using the number of seconds since Epoch UTC (Jan 1st 1970 00h00m00s000 GMT) to now (GMT), plus the 'sas_token_lifetime'.]
+		size_t new_expiry_time = currentTimeInSeconds + (transport_state->cbs.sas_token_lifetime / 1000);
 
-    STRING_HANDLE newSASToken;
+		STRING_HANDLE newSASToken;
 
-    switch (transport_state->credential.credentialType)
-    {
-    default:
-    {
-        result = __LINE__;
-        LogError("internal error, unexpected enum value transport_state->credential.credentialType=%d", transport_state->credential.credentialType);
-        break;
-    }
-    case DEVICE_KEY:
-    {
-        newSASToken = SASToken_Create(transport_state->credential.credential.deviceKey, transport_state->devicesPath, transport_state->cbs.sasTokenKeyName, new_expiry_time);
-        if (newSASToken == NULL)
-        {
-            LogError("Could not generate a new SAS token for the CBS.");
-            result = RESULT_FAILURE;
-        }
-        else
-        {
-            if (handSASTokenToCbs(transport_state, newSASToken, sas_token_create_time) != 0)
-            {
-                LogError("unable to handSASTokenToCbs");
-                result = RESULT_FAILURE;
-            }
-            else
-            {
-                result = RESULT_OK;
-            }
+		switch (transport_state->credential.credentialType)
+		{
+			default:
+			{
+				result = __LINE__;
+				LogError("internal error, unexpected enum value transport_state->credential.credentialType=%d", transport_state->credential.credentialType);
+				break;
+			}
+			case DEVICE_KEY:
+			{
+				newSASToken = SASToken_Create(transport_state->credential.credential.deviceKey, transport_state->devicesPath, transport_state->cbs.sasTokenKeyName, new_expiry_time);
+				if (newSASToken == NULL)
+				{
+					LogError("Could not generate a new SAS token for the CBS.");
+					result = RESULT_FAILURE;
+				}
+				else
+				{
+					if (handSASTokenToCbs(transport_state, newSASToken, currentTimeInSeconds) != 0)
+					{
+						LogError("unable to handSASTokenToCbs");
+						result = RESULT_FAILURE;
+					}
+					else
+					{
+						result = RESULT_OK;
+					}
 
-            // Codes_SRS_IOTHUBTRANSPORTAMQP_09_145: [Each new SAS token created shall be deleted from memory immediately after sending it to CBS]
-            STRING_delete(newSASToken);
-        }
-        break;
-    }
-    case DEVICE_SAS_TOKEN:
-    {
-        newSASToken = STRING_clone(transport_state->credential.credential.deviceSasToken);
-        if (newSASToken == NULL)
-        {
-            LogError("Could not generate a new SAS token for the CBS.");
-            result = RESULT_FAILURE;
-        }
-        else
-        {
-            if (handSASTokenToCbs(transport_state, newSASToken, sas_token_create_time) != 0)
-            {
-                LogError("unable to handSASTokenToCbs");
-                result = RESULT_FAILURE;
-            }
-            else
-            {
-                result = RESULT_OK;
-            }
+					// Codes_SRS_IOTHUBTRANSPORTAMQP_09_145: [Each new SAS token created shall be deleted from memory immediately after sending it to CBS]
+					STRING_delete(newSASToken);
+				}
+				break;
+			}
+			case DEVICE_SAS_TOKEN:
+			{
+				newSASToken = STRING_clone(transport_state->credential.credential.deviceSasToken);
+				if (newSASToken == NULL)
+				{
+					LogError("Could not generate a new SAS token for the CBS.");
+					result = RESULT_FAILURE;
+				}
+				else
+				{
+					if (handSASTokenToCbs(transport_state, newSASToken, currentTimeInSeconds) != 0)
+					{
+						LogError("unable to handSASTokenToCbs");
+						result = RESULT_FAILURE;
+					}
+					else
+					{
+						result = RESULT_OK;
+					}
 
-            // Codes_SRS_IOTHUBTRANSPORTAMQP_09_145: [Each new SAS token created shall be deleted from memory immediately after sending it to CBS]
-            STRING_delete(newSASToken);
-        }
-        break;
-    }
-    }
+					// Codes_SRS_IOTHUBTRANSPORTAMQP_09_145: [Each new SAS token created shall be deleted from memory immediately after sending it to CBS]
+					STRING_delete(newSASToken);
+				}
+				break;
+			}
+		}
+	}
     return result;
 }
 
 static int verifyAuthenticationTimeout(AMQP_TRANSPORT_INSTANCE* transport_state)
 {
-    return ((getSecondsSinceEpoch() - transport_state->cbs.current_sas_token_create_time) * 1000 >= transport_state->cbs.cbs_request_timeout) ? RESULT_TIMEOUT : RESULT_OK;
+	int result;
+	size_t currentTimeInSeconds;
+	if (getSecondsSinceEpoch(&currentTimeInSeconds) != RESULT_OK)
+	{
+		LogError("Failed getting the current time to verify if the SAS token needs to be refreshed.");
+		result = RESULT_TIMEOUT; // Fail safe.
+	}
+	else
+	{
+		result = ((currentTimeInSeconds - transport_state->cbs.current_sas_token_create_time) * 1000 >= transport_state->cbs.cbs_request_timeout) ? RESULT_TIMEOUT : RESULT_OK;
+	}
+	return result;
 }
 
 static void attachDeviceClientTypeToLink(LINK_HANDLE link)
@@ -1482,14 +1533,23 @@
 
 static bool isSasTokenRefreshRequired(AMQP_TRANSPORT_INSTANCE* transport_state)
 {
+	bool result;
+	size_t currentTimeInSeconds;
     if (transport_state->credential.credentialType == DEVICE_SAS_TOKEN)
     {
-        return false;
+        result = false;
     }
+	else if (getSecondsSinceEpoch(&currentTimeInSeconds) != RESULT_OK)
+	{
+		LogError("Failed getting the current time to verify if the SAS token needs to be refreshed.");
+		result = true; // Fail safe.
+	}
     else
     {
-        return ((getSecondsSinceEpoch() - transport_state->cbs.current_sas_token_create_time) >= (transport_state->cbs.sas_token_refresh_time / 1000)) ? true : false;
+        result = ((currentTimeInSeconds - transport_state->cbs.current_sas_token_create_time) >= (transport_state->cbs.sas_token_refresh_time / 1000)) ? true : false;
     }
+	
+	return result;
 }
 
 static void prepareForConnectionRetry(AMQP_TRANSPORT_INSTANCE* transport_state)
@@ -2130,6 +2190,10 @@
 
 static IOTHUB_DEVICE_HANDLE IoTHubTransportAMQP_Register(TRANSPORT_LL_HANDLE handle, const IOTHUB_DEVICE_CONFIG* device, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, PDLIST_ENTRY waitingToSend)
 {
+#ifdef NO_LOGGING
+    UNUSED(iotHubClientHandle);
+#endif
+
     IOTHUB_DEVICE_HANDLE result;
     // Codes_SRS_IOTHUBTRANSPORTAMQP_17_001: [IoTHubTransportAMQP_Register shall return NULL if device, or waitingToSend are NULL.] 
     // Codes_SRS_IOTHUBTRANSPORTAMQP_17_005: [IoTHubTransportAMQP_Register shall return NULL if the TRANSPORT_LL_HANDLE is NULL.]