Microsoft Azure IoTHub client HTTP transport
Dependents: iothub_client_sample_http simplesample_http temp_sensor_anomaly
This library implements the HTTP transport for Microsoft Azure IoTHub client. The code is replicated from https://github.com/Azure/azure-iot-sdks
Diff: iothubtransporthttp.c
- Revision:
- 3:4e9296134ffb
- Parent:
- 2:ff9104b866b8
- Child:
- 4:ce756a949fbd
--- a/iothubtransporthttp.c Wed Sep 16 22:42:49 2015 -0700 +++ b/iothubtransporthttp.c Tue Sep 22 20:36:43 2015 -0700 @@ -28,11 +28,13 @@ #define APPLICATION_OCTET_STREAM "application/octet-stream" #define APPLICATION_VND_MICROSOFT_IOTHUB_JSON "application/vnd.microsoft.iothub.json" -/*DEFAULT_GETMINIMUMPOLLINGTIME is the minimum time in seconds allowed between 2 consecutive GET issues to the service (GET=fetch notifications)*/ +/*DEFAULT_GETMINIMUMPOLLINGTIME is the minimum time in seconds allowed between 2 consecutive GET issues to the service (GET=fetch messages)*/ /*the default is 25 minutes*/ #define DEFAULT_GETMINIMUMPOLLINGTIME ((unsigned int)25*60) #define MAXIMUM_MESSAGE_SIZE (255*1024-1) +#define MAXIMUM_PAYLOAD_OVERHEAD 384 +#define MAXIMUM_PROPERTY_OVERHEAD 16 /*forward declaration*/ static int appendMapToJSON(STRING_HANDLE existing, const char* const* keys, const char* const* values, size_t count); @@ -49,7 +51,7 @@ IoTHubTransportHttp_GetSendStatus /* pfIoTHubTransport_GetSendStatus IoTHubTransport_GetSendStatus */ }; -const void* IoTHubTransportHttp_ProvideTransportInterface(void) +const void* HTTP_Protocol(void) { return &thisTransportProvider; } @@ -57,14 +59,14 @@ typedef struct HTTPTRANSPORT_HANDLE_DATA_TAG { STRING_HANDLE eventHTTPrelativePath; - STRING_HANDLE notificationHTTPrelativePath; + STRING_HANDLE messageHTTPrelativePath; HTTP_HEADERS_HANDLE eventHTTPrequestHeaders; STRING_HANDLE hostName; HTTPAPIEX_HANDLE httpApiExHandle; - HTTP_HEADERS_HANDLE notificationHTTPrequestHeaders; + HTTP_HEADERS_HANDLE messageHTTPrequestHeaders; STRING_HANDLE abandonHTTPrelativePathBegin; HTTPAPIEX_SAS_HANDLE sasObject; - bool DoWork_PullNotification; + bool DoWork_PullMessage; bool doBatchedTransfers; bool isFirstPoll; unsigned int getMinimumPollingTime; @@ -108,19 +110,19 @@ return result; } -/*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_034: [Otherwise, IoTHubTransportHttp_Create shall create an immutable string (further called "notification HTTP relative path") from the following pieces: "/devices/" + URL_ENCODED(config->upperConfig->deviceId) + "/messages/devicebound?api-version=2015-08-15-preview".]*/ -static void destroy_notificationHTTPrelativePath(HTTPTRANSPORT_HANDLE_DATA* handleData) +/*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_034: [Otherwise, IoTHubTransportHttp_Create shall create an immutable string (further called "message HTTP relative path") from the following pieces: "/devices/" + URL_ENCODED(config->upperConfig->deviceId) + "/messages/devicebound?api-version=2015-08-15-preview".]*/ +static void destroy_messageHTTPrelativePath(HTTPTRANSPORT_HANDLE_DATA* handleData) { - STRING_delete(handleData->notificationHTTPrelativePath); - handleData->notificationHTTPrelativePath = NULL; + STRING_delete(handleData->messageHTTPrelativePath); + handleData->messageHTTPrelativePath = NULL; } -/*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_034: [Otherwise, IoTHubTransportHttp_Create shall create an immutable string (further called "notification HTTP relative path") from the following pieces: "/devices/" + URL_ENCODED(config->upperConfig->deviceId) + "/messages/devicebound?api-version=2015-08-15-preview".]*/ -static bool create_notificationHTTPrelativePath(HTTPTRANSPORT_HANDLE_DATA* handleData, const IOTHUBTRANSPORT_CONFIG* config) +/*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_034: [Otherwise, IoTHubTransportHttp_Create shall create an immutable string (further called "message HTTP relative path") from the following pieces: "/devices/" + URL_ENCODED(config->upperConfig->deviceId) + "/messages/devicebound?api-version=2015-08-15-preview".]*/ +static bool create_messageHTTPrelativePath(HTTPTRANSPORT_HANDLE_DATA* handleData, const IOTHUBTRANSPORT_CONFIG* config) { bool result; - handleData->notificationHTTPrelativePath = STRING_construct("/devices/"); - if (handleData->notificationHTTPrelativePath == NULL) + handleData->messageHTTPrelativePath = STRING_construct("/devices/"); + if (handleData->messageHTTPrelativePath == NULL) { result = false; } @@ -129,12 +131,12 @@ STRING_HANDLE urlEncodedDeviceId = NULL; if (!( ((urlEncodedDeviceId = URL_EncodeString(config->upperConfig->deviceId)) != NULL) && - (STRING_concat_with_STRING(handleData->notificationHTTPrelativePath, urlEncodedDeviceId) == 0) && - (STRING_concat(handleData->notificationHTTPrelativePath, NOTIFICATION_ENDPOINT_HTTP API_VERSION) == 0) + (STRING_concat_with_STRING(handleData->messageHTTPrelativePath, urlEncodedDeviceId) == 0) && + (STRING_concat(handleData->messageHTTPrelativePath, MESSAGE_ENDPOINT_HTTP API_VERSION) == 0) )) { result = false; - destroy_notificationHTTPrelativePath(handleData); + destroy_messageHTTPrelativePath(handleData); } else { @@ -272,30 +274,30 @@ return result; } -/*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_059: [Otherwise, IoTHubTransportHttp_Create shall create a set of HTTP headers (further on called "notification HTTP request headers") consisting of the following fixed field names and values: +/*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_059: [Otherwise, IoTHubTransportHttp_Create shall create a set of HTTP headers (further on called "message HTTP request headers") consisting of the following fixed field names and values: "Authorization": " "]*/ -static void destroy_notificationHTTPrequestHeaders(HTTPTRANSPORT_HANDLE_DATA* handleData) +static void destroy_messageHTTPrequestHeaders(HTTPTRANSPORT_HANDLE_DATA* handleData) { - HTTPHeaders_Free(handleData->notificationHTTPrequestHeaders); - handleData->notificationHTTPrequestHeaders = NULL; + HTTPHeaders_Free(handleData->messageHTTPrequestHeaders); + handleData->messageHTTPrequestHeaders = NULL; } -/*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_059: [Otherwise, IoTHubTransportHttp_Create shall create a set of HTTP headers (further on called "notification HTTP request headers") consisting of the following fixed field names and values: +/*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_059: [Otherwise, IoTHubTransportHttp_Create shall create a set of HTTP headers (further on called "message HTTP request headers") consisting of the following fixed field names and values: "Authorization": " "]*/ -static bool create_notificationHTTPrequestHeaders(HTTPTRANSPORT_HANDLE_DATA* handleData, const IOTHUBTRANSPORT_CONFIG* config) +static bool create_messageHTTPrequestHeaders(HTTPTRANSPORT_HANDLE_DATA* handleData, const IOTHUBTRANSPORT_CONFIG* config) { bool result; (void)config; - handleData->notificationHTTPrequestHeaders = HTTPHeaders_Alloc(); - if (handleData->notificationHTTPrequestHeaders == NULL) + handleData->messageHTTPrequestHeaders = HTTPHeaders_Alloc(); + if (handleData->messageHTTPrequestHeaders == NULL) { result = false; } else { - if (HTTPHeaders_AddHeaderNameValuePair(handleData->notificationHTTPrequestHeaders, "Authorization", " ") != HTTP_HEADERS_OK) + if (HTTPHeaders_AddHeaderNameValuePair(handleData->messageHTTPrequestHeaders, "Authorization", " ") != HTTP_HEADERS_OK) { - destroy_notificationHTTPrequestHeaders(handleData); + destroy_messageHTTPrequestHeaders(handleData); result = false; } else @@ -328,7 +330,7 @@ if (!( ((urlEncodedDeviceId = URL_EncodeString(config->upperConfig->deviceId)) != NULL) && (STRING_concat_with_STRING(handleData->abandonHTTPrelativePathBegin, urlEncodedDeviceId) == 0) && - (STRING_concat(handleData->abandonHTTPrelativePathBegin, NOTIFICATION_ENDPOINT_HTTP_ETAG) == 0) + (STRING_concat(handleData->abandonHTTPrelativePathBegin, MESSAGE_ENDPOINT_HTTP_ETAG) == 0) )) { LogError("unable to STRING_concat\r\n"); @@ -472,18 +474,18 @@ else { bool was_eventHTTPrelativePath_ok = create_eventHTTPrelativePath(result, config); - bool was_notificationHTTPrelativePath_ok = was_eventHTTPrelativePath_ok && create_notificationHTTPrelativePath(result, config); - bool was_eventHTTPrequestHeaders_ok = was_notificationHTTPrelativePath_ok && create_eventHTTPrequestHeaders(result, config); + bool was_messageHTTPrelativePath_ok = was_eventHTTPrelativePath_ok && create_messageHTTPrelativePath(result, config); + bool was_eventHTTPrequestHeaders_ok = was_messageHTTPrelativePath_ok && create_eventHTTPrequestHeaders(result, config); bool was_hostName_ok = was_eventHTTPrequestHeaders_ok && create_hostName(result, config); bool was_httpApiExHandle_ok = was_hostName_ok && create_httpApiExHandle(result, config); - bool was_notificationHTTPrequestHeaders_ok = was_httpApiExHandle_ok && create_notificationHTTPrequestHeaders(result, config); - bool was_abandonHTTPrelativePathBegin_ok = was_notificationHTTPrequestHeaders_ok && create_abandonHTTPrelativePathBegin(result, config); + bool was_messageHTTPrequestHeaders_ok = was_httpApiExHandle_ok && create_messageHTTPrequestHeaders(result, config); + bool was_abandonHTTPrelativePathBegin_ok = was_messageHTTPrequestHeaders_ok && create_abandonHTTPrelativePathBegin(result, config); bool was_sasObject_ok = was_abandonHTTPrelativePathBegin_ok && create_deviceSASObject(result, config); - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_011: [Otherwise, IoTHubTransportHttp_Create shall set a flag called "DoWork_PullNotification" to false, succeed and return a non-NULL value.]*/ + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_011: [Otherwise, IoTHubTransportHttp_Create shall set a flag called "DoWork_PullMessage" to false, succeed and return a non-NULL value.]*/ if (was_sasObject_ok) { - result->DoWork_PullNotification = false; + result->DoWork_PullMessage = false; result->doBatchedTransfers = false; result->isFirstPoll = true; result->getMinimumPollingTime = DEFAULT_GETMINIMUMPOLLINGTIME; @@ -494,16 +496,16 @@ { /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_004: [If creating the string fail for any reason then IoTHubTransportHttp_Create shall fail and return NULL.] */ if (was_eventHTTPrelativePath_ok) destroy_eventHTTPrelativePath(result); - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_035: [If creating the notification HTTP relative path fails, then IoTHubTransportHttp_Create shall fail and return NULL.] */ - if (was_notificationHTTPrelativePath_ok) destroy_notificationHTTPrelativePath(result); + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_035: [If creating the message HTTP relative path fails, then IoTHubTransportHttp_Create shall fail and return NULL.] */ + if (was_messageHTTPrelativePath_ok) destroy_messageHTTPrelativePath(result); /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_006: [If creating the event HTTP request headers fails, then IoTHubTransportHttp_Create shall fail and return NULL.] */ if (was_eventHTTPrequestHeaders_ok) destroy_eventHTTPrequestHeaders(result); /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_008: [If creating the hostname fails then IoTHubTransportHttp_Create shall fail and return NULL.] */ if (was_hostName_ok) destroy_hostName(result); /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_010: [If creating the HTTPAPIEX_HANDLE fails then IoTHubTransportHttp_Create shall fail and return NULL.] */ if (was_httpApiExHandle_ok) destroy_httpApiExHandle(result); - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_060: [If creating notification HTTP request headers then IoTHubTransportHttp_Create shall fail and return NULL.]*/ - if (was_notificationHTTPrequestHeaders_ok) destroy_notificationHTTPrequestHeaders(result); + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_060: [If creating message HTTP request headers then IoTHubTransportHttp_Create shall fail and return NULL.]*/ + if (was_messageHTTPrequestHeaders_ok) destroy_messageHTTPrequestHeaders(result); /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_062: [If creating the abandonHTTPrelativePathBegin fails then IoTHubTransportHttp_Create shall fail and return NULL] */ if (was_abandonHTTPrelativePathBegin_ok) destroy_abandonHTTPrelativePathBegin(result); @@ -522,11 +524,11 @@ { /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_013: [Otherwise IoTHubTransportHttp_Destroy shall free all the resources currently in use.] */ destroy_eventHTTPrelativePath(handle); - destroy_notificationHTTPrelativePath(handle); + destroy_messageHTTPrelativePath(handle); destroy_eventHTTPrequestHeaders(handle); destroy_hostName(handle); destroy_httpApiExHandle(handle); - destroy_notificationHTTPrequestHeaders(handle); + destroy_messageHTTPrequestHeaders(handle); destroy_abandonHTTPrelativePathBegin(handle); destroy_SASObject(handle); free(handle); @@ -544,9 +546,9 @@ } else { - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_056: [Otherwise, IoTHubTransportHttp_Subscribe shall set the flag called DoWork_PullNotifications to true and succeed.] */ + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_056: [Otherwise, IoTHubTransportHttp_Subscribe shall set the flag called DoWork_PullMessages to true and succeed.] */ HTTPTRANSPORT_HANDLE_DATA* handleData = (HTTPTRANSPORT_HANDLE_DATA*)handle; - handleData->DoWork_PullNotification = true; + handleData->DoWork_PullMessage = true; result = 0; } return result; @@ -558,14 +560,14 @@ if (handle != NULL) { HTTPTRANSPORT_HANDLE_DATA* handleData = (HTTPTRANSPORT_HANDLE_DATA*)handle; - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_058: [Otherwise it shall set the flag DoWork_PullNotification to false.] */ - handleData->DoWork_PullNotification = false; + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_058: [Otherwise it shall set the flag DoWork_PullMessage to false.] */ + handleData->DoWork_PullMessage = false; } } /*produces a representation of the properties, if they exist*/ /*if they do not exist, produces ""*/ -static int concat_Properties(STRING_HANDLE existing, MAP_HANDLE map) +static int concat_Properties(STRING_HANDLE existing, MAP_HANDLE map, size_t* propertiesMessageSizeContribution) { int result; const char*const* keys; @@ -584,6 +586,7 @@ /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_076: [If IoTHubMessage does not have properties, then "properties":{...} shall be missing from the payload*/ /*no properties - do nothing with existing*/ result = 0; + *propertiesMessageSizeContribution = 0; } else { @@ -602,6 +605,13 @@ else { /*all is fine*/ + size_t i; + *propertiesMessageSizeContribution = 0; + for (i = 0;i < count;i++) + { + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_120: [Every property name shall add to the message size the length of the property name + the length of the property value + 16 bytes.] */ + *propertiesMessageSizeContribution += (strlen(keys[i]) + strlen(values[i]) + MAXIMUM_PROPERTY_OVERHEAD); + } result = 0; } } @@ -658,11 +668,12 @@ /*makes the following string:{"body":"base64 encoding of the message content"[,"properties":{"a":"valueOfA"}]}*/ /*return NULL if there was a failure, or a non-NULL STRING_HANDLE that contains the intended data*/ -static STRING_HANDLE make1EventJSONitem(PDLIST_ENTRY item) +static STRING_HANDLE make1EventJSONitem(PDLIST_ENTRY item, size_t *messageSizeContribution) { STRING_HANDLE result; /*temp wants to contain :{"body":"base64 encoding of the message content"[,"properties":{"a":"valueOfA"}]}*/ IOTHUB_MESSAGE_LIST* message = containingRecord(item, IOTHUB_MESSAGE_LIST, entry); IOTHUBMESSAGE_CONTENT_TYPE contentType = IoTHubMessage_GetContentType(message->messageHandle); + switch (contentType) { case IOTHUBMESSAGE_BYTEARRAY: @@ -694,10 +705,11 @@ } else { + size_t propertiesSize; if (!( (STRING_concat_with_STRING(result, encoded) == 0) && (STRING_concat(result, "\"") == 0) && /*\" because closing value*/ - (concat_Properties(result, IoTHubMessage_Properties(message->messageHandle)) == 0) && + (concat_Properties(result, IoTHubMessage_Properties(message->messageHandle), &propertiesSize) == 0) && (STRING_concat(result, "},") == 0) /*the last comma shall be replaced by a ']' by DaCr's suggestion (which is awesome enough to receive credits in the source code)*/ )) { @@ -708,6 +720,8 @@ else { /*all is fine... */ + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_119: [The message size is computed from the length of the payload + 384.] */ + *messageSizeContribution = size + MAXIMUM_PAYLOAD_OVERHEAD + propertiesSize; } STRING_delete(encoded); } @@ -743,10 +757,11 @@ } else { + size_t propertiesSize; if (!( (STRING_concat_with_STRING(result, asJson) == 0) && (STRING_concat(result, ",\"base64Encoded\":false") == 0) && - (concat_Properties(result, IoTHubMessage_Properties(message->messageHandle)) == 0) && + (concat_Properties(result, IoTHubMessage_Properties(message->messageHandle), &propertiesSize) == 0) && (STRING_concat(result, "},") == 0) /*the last comma shall be replaced by a ']' by DaCr's suggestion (which is awesome enough to receive credits in the source code)*/ )) { @@ -757,6 +772,8 @@ else { /*result has the intended content*/ + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_119: [The message size is computed from the length of the payload + 384.] */ + *messageSizeContribution = strlen(source) + MAXIMUM_PAYLOAD_OVERHEAD + propertiesSize; } STRING_delete(asJson); } @@ -787,7 +804,7 @@ static MAKE_PAYLOAD_RESULT makePayload(HTTPTRANSPORT_HANDLE_DATA* handleData, STRING_HANDLE* payload) { MAKE_PAYLOAD_RESULT result; - + size_t allMessagesSize = 0; *payload = STRING_construct("["); if (*payload == NULL) { @@ -803,7 +820,8 @@ bool keepGoing = true; /*keepGoing gets sometimes to false from within the loop*/ while (keepGoing && ((actual = handleData->waitingToSend->Flink) != handleData->waitingToSend)) { - STRING_HANDLE temp = make1EventJSONitem(actual); + size_t messageSize; + STRING_HANDLE temp = make1EventJSONitem(actual, &messageSize); if (isFirst) { isFirst = false; @@ -818,7 +836,8 @@ else { /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_071: [If the oldest message in waitingToSend causes the message size to exceed the message size limit then it shall be removed from waitingToSend, and IoTHubClient_LL_SendComplete shall be called. Parameter PDLIST_ENTRY completed shall point to a list containing only the oldest item, and parameter IOTHUB_BATCHSTATE result shall be set to IOTHUB_BATCHSTATE_FAILED.]*/ - if (STRING_length(temp) >= MAXIMUM_MESSAGE_SIZE) + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_118: [The message size shall be limited to 255KB - 1 byte.]*/ + if (messageSize > MAXIMUM_MESSAGE_SIZE) { PDLIST_ENTRY head = DList_RemoveHeadList(handleData->waitingToSend); /*actually this is the same as "actual", but now it is removed*/ DList_InsertTailList(&(handleData->eventConfirmations), head); @@ -842,6 +861,7 @@ /*first item was put nicely in the payload*/ PDLIST_ENTRY head = DList_RemoveHeadList(handleData->waitingToSend); /*actually this is the same as "actual", but now it is removed*/ DList_InsertTailList(&(handleData->eventConfirmations), head); + allMessagesSize += messageSize; } } STRING_delete(temp); @@ -859,7 +879,7 @@ } else { - if (STRING_length(*payload) + STRING_length(temp) > MAXIMUM_MESSAGE_SIZE) + if (allMessagesSize + messageSize > MAXIMUM_MESSAGE_SIZE) { /*this item doesn't make it to the payload, but the payload is valid so far*/ /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_072: [If at any point during construction of the string there are errors, IoTHubTransportHttp_DoWork shall use the so far constructed string as payload.]*/ @@ -878,6 +898,7 @@ /*cool, the payload made it there, let's continue... */ PDLIST_ENTRY head = DList_RemoveHeadList(handleData->waitingToSend); /*actually this is the same as "actual", but now it is removed*/ DList_InsertTailList(&(handleData->eventConfirmations), head); + allMessagesSize += messageSize; } STRING_delete(temp); } @@ -1017,16 +1038,22 @@ } else { - const unsigned char* messageContent; - size_t messageSize; + const unsigned char* messageContent=NULL; + size_t messageSize=0; + size_t originalMessageSize=0; IOTHUB_MESSAGE_LIST* message = containingRecord(handleData->waitingToSend->Flink, IOTHUB_MESSAGE_LIST, entry); IOTHUBMESSAGE_CONTENT_TYPE contentType = IoTHubMessage_GetContentType(message->messageHandle); + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_122: [The message size is computed from the length of the payload + 384.]*/ if (!( - ((contentType == IOTHUBMESSAGE_BYTEARRAY) && (IoTHubMessage_GetByteArray(message->messageHandle, &messageContent, &messageSize)==IOTHUB_MESSAGE_OK)) || + (((contentType == IOTHUBMESSAGE_BYTEARRAY) && + (IoTHubMessage_GetByteArray(message->messageHandle, &messageContent, &originalMessageSize)==IOTHUB_MESSAGE_OK)) ? (messageSize= originalMessageSize + MAXIMUM_PAYLOAD_OVERHEAD, 1): 0) + + || + ((contentType == IOTHUBMESSAGE_STRING) && ( messageContent = (const unsigned char*)IoTHubMessage_GetString(message->messageHandle), - (messageSize = (messageContent == NULL)?0:strlen((const char*)messageContent)), + (messageSize = MAXIMUM_PAYLOAD_OVERHEAD + (originalMessageSize = ((messageContent == NULL)?0:strlen((const char*)messageContent)))), messageContent!=NULL) ) )) @@ -1037,7 +1064,8 @@ else { /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_109: [If the oldest message in waitingToSend causes the message to exceed the message size limit then it shall be removed from waitingToSend, and IoTHubClient_LL_SendComplete shall be called. Parameter PDLIST_ENTRY completed shall point to a list containing only the oldest item, and parameter IOTHUB_BATCHSTATE result shall be set to IOTHUB_BATCHSTATE_FAILED.]*/ - if (messageSize >= MAXIMUM_MESSAGE_SIZE) + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_121: [The message size shall be limited to 255KB -1 bytes.] */ + if (messageSize > MAXIMUM_MESSAGE_SIZE) { PDLIST_ENTRY head = DList_RemoveHeadList(handleData->waitingToSend); /*actually this is the same as "actual", but now it is removed*/ DList_InsertTailList(&(handleData->eventConfirmations), head); @@ -1079,32 +1107,44 @@ bool goOn = true; for (i = 0; (i < count) && goOn; i++) { - - STRING_HANDLE temp = STRING_construct(IOTHUB_APP_PREFIX); - if (temp == NULL) + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_123: [Every property name shall add to the message size the length of the property name + the length of the property value + 16 bytes.] */ + messageSize += (strlen(values[i]) + strlen(keys[i]) + MAXIMUM_PROPERTY_OVERHEAD); + if (messageSize > MAXIMUM_MESSAGE_SIZE) { - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_108: [If any HTTP header operation fails, _DoWork shall advance to the next action.] */ - LogError("unable to STRING_construct\r\n"); + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_121: [The message size shall be limited to 255KB -1 bytes.] */ + PDLIST_ENTRY head = DList_RemoveHeadList(handleData->waitingToSend); /*actually this is the same as "actual", but now it is removed*/ + DList_InsertTailList(&(handleData->eventConfirmations), head); + IoTHubClient_LL_SendComplete(iotHubClientHandle, &(handleData->eventConfirmations), IOTHUB_BATCHSTATE_FAILED); /*takes care of emptying the list too*/ goOn = false; } else { - if (STRING_concat(temp, keys[i]) != 0) + STRING_HANDLE temp = STRING_construct(IOTHUB_APP_PREFIX); + if (temp == NULL) { /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_108: [If any HTTP header operation fails, _DoWork shall advance to the next action.] */ - LogError("unable to STRING_concat\r\n"); + LogError("unable to STRING_construct\r\n"); goOn = false; } else { - if (HTTPHeaders_ReplaceHeaderNameValuePair(clonedEventHTTPrequestHeaders, STRING_c_str(temp), values[i]) != HTTP_HEADERS_OK) + if (STRING_concat(temp, keys[i]) != 0) { /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_108: [If any HTTP header operation fails, _DoWork shall advance to the next action.] */ - LogError("unable to HTTPHeaders_ReplaceHeaderNameValuePair\r\n"); + LogError("unable to STRING_concat\r\n"); goOn = false; } + else + { + if (HTTPHeaders_ReplaceHeaderNameValuePair(clonedEventHTTPrequestHeaders, STRING_c_str(temp), values[i]) != HTTP_HEADERS_OK) + { + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_108: [If any HTTP header operation fails, _DoWork shall advance to the next action.] */ + LogError("unable to HTTPHeaders_ReplaceHeaderNameValuePair\r\n"); + goOn = false; + } + } + STRING_delete(temp); } - STRING_delete(temp); } } @@ -1122,7 +1162,7 @@ } else { - if (BUFFER_build(toBeSend, messageContent, messageSize) != 0) + if (BUFFER_build(toBeSend, messageContent, originalMessageSize) != 0) { LogError("unable to BUFFER_build\r\n"); } @@ -1311,11 +1351,11 @@ } } -static void DoNotifications(TRANSPORT_HANDLE handle, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle) +static void DoMessages(TRANSPORT_HANDLE handle, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle) { HTTPTRANSPORT_HANDLE_DATA* handleData = (HTTPTRANSPORT_HANDLE_DATA*)handle; - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_057: [If flag DoWork_PullNotification is set to false then _DoWork shall advance to the next action.] */ - if (handleData->DoWork_PullNotification) + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_057: [If flag DoWork_PullMessage is set to false then _DoWork shall advance to the next action.] */ + if (handleData->DoWork_PullMessage) { /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_116: [After client creation, the first GET shall be allowed no matter what the value of GetMinimumPollingTime.] */ /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_117: [If time is not available then all calls shall be treated as if they are the first one.] */ @@ -1343,8 +1383,8 @@ unsigned int statusCode; /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_036: [Otherwise, IoTHubTransportHttp_DoWork shall call HTTPAPIEX_SAS_ExecuteRequest passing the following parameters requestType: GET -relativePath: the notification HTTP relative path -requestHttpHeadersHandle: notification HTTP request headers created by _Create +relativePath: the message HTTP relative path +requestHttpHeadersHandle: message HTTP request headers created by _Create requestContent: NULL statusCode: a pointer to unsigned int which shall be later examined responseHeadearsHandle: a new instance of HTTP headers @@ -1354,8 +1394,8 @@ handleData->sasObject, handleData->httpApiExHandle, HTTPAPI_REQUEST_GET, /*requestType: GET*/ - STRING_c_str(handleData->notificationHTTPrelativePath), /*relativePath: the notification HTTP relative path*/ - handleData->notificationHTTPrequestHeaders, /*requestHttpHeadersHandle: notification HTTP request headers created by _Create*/ + STRING_c_str(handleData->messageHTTPrelativePath), /*relativePath: the message HTTP relative path*/ + handleData->messageHTTPrequestHeaders, /*requestHttpHeadersHandle: message HTTP request headers created by _Create*/ NULL, /*requestContent: NULL*/ &statusCode, /*statusCode: a pointer to unsigned int which shall be later examined*/ responseHTTPHeaders, /*responseHeadearsHandle: a new instance of HTTP headers*/ @@ -1464,21 +1504,21 @@ } else { - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_043: [Otherwise, _DoWork shall call IoTHubClient_LL_NotificationCallback with parameters handle = iotHubClientHandle and notificationMessage = newly created message.]*/ - IOTHUBMESSAGE_DISPOSITION_RESULT notificationResult = IoTHubClient_LL_NotificationCallback(iotHubClientHandle, receivedMessage); - if (notificationResult == IOTHUBMESSAGE_ACCEPTED) + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_043: [Otherwise, _DoWork shall call IoTHubClient_LL_MessageCallback with parameters handle = iotHubClientHandle and message = newly created message.]*/ + IOTHUBMESSAGE_DISPOSITION_RESULT messageResult = IoTHubClient_LL_MessageCallback(iotHubClientHandle, receivedMessage); + if (messageResult == IOTHUBMESSAGE_ACCEPTED) { - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_044: [If IoTHubClient_LL_NotificationCallback returns IOTHUBMESSAGE_ACCEPTED then _DoWork shall "accept" the message.]*/ + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_044: [If IoTHubClient_LL_MessageCallback returns IOTHUBMESSAGE_ACCEPTED then _DoWork shall "accept" the message.]*/ abandonOrAcceptMessage(handle, etagValue, ACCEPT); } - else if (notificationResult == IOTHUBMESSAGE_REJECTED) + else if (messageResult == IOTHUBMESSAGE_REJECTED) { - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_074: [If IoTHubClient_LL_NotificationCallback returns IOTHUBMESSAGE_REJECTED then _DoWork shall "reject" the message.]*/ + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_074: [If IoTHubClient_LL_MessageCallback returns IOTHUBMESSAGE_REJECTED then _DoWork shall "reject" the message.]*/ abandonOrAcceptMessage(handle, etagValue, REJECT); } else { - /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_079: [If IoTHubClient_LL_NotificationCallback returns IOTHUBMESSAGE_ABANDONED then _DoWork shall "abandon" the message.] */ + /*Codes_SRS_IOTHUBTRANSPORTTHTTP_02_079: [If IoTHubClient_LL_MessageCallback returns IOTHUBMESSAGE_ABANDONED then _DoWork shall "abandon" the message.] */ abandonOrAcceptMessage(handle, etagValue, ABANDON); } } @@ -1509,7 +1549,7 @@ if ((handle != NULL) && (iotHubClientHandle != NULL)) { DoEvent(handle, iotHubClientHandle); - DoNotifications(handle, iotHubClientHandle); + DoMessages(handle, iotHubClientHandle); } }