I'm trying to implement an Azure IOT hub connection with MQTT using a custom WiFi driver. Has anyone else had any experience with this as I am having some problems?
My problem seems to be with the Azure SDK part of it, I know the WiFI driver is functioning correctly as I've already been using it with the Paho MQTT packet and the Eclipse broker.
I have my iot socket functions currently stubbed off and the first one that seems to get called is iotSocketGetHostByName() with the first argument being a pointer to the broker URL, but the URL is empty.
I believe I have setup the connection string correctly and I can step through the code to see that the url of the azure iot hub is being extracted correctly and is being stored. However it doesn't get passed to the iotSocketGetHostByName() function as it's not stored in the dns->hostname variable.
Any thoughts please.
It might be also that you don't have enough heap.
You should debug the application to see where it breaks.
DNS resolver is started first in the function dns_async_create (module: c-utility\pal\mdk\dns_async.c). The function receives the "hostname" string which is copied to allocated memory for DNS instance. Check if "hostname" is a valid string and if it gets copied to DNS->hostname.
if (hostname == NULL) { ... } else { result = malloc(sizeof(DNS_ASYNC_INSTANCE)); if (result == NULL) { } else { ... mallocAndStrcpy_s(&result->hostname, hostname); ... }
It could be that the allocation fails in the function or hostname was already NULL due to some issue before that.
Depending on that you should investigate further.
Call chain: iothub_client\src\iothubtransport_mqtt_common.c\IoTHubTransport_MQTT_Common_DoWork >InitializeConnection(PMQTTTRANSPORT_HANDLE_DATA transport_data) transport_data->hostAddress should contain the string pointer to hostname >> umqtt\src\mqtt_client.c\mqtt_client_connect() >>> c-utility\src\xio.c\xio_open >>>> c-utility\pal\mdk\tlsio_mbedtls.c\tlsio_mbedtls_open >>>>> c-utility\pal\mdk\dns_async.c\dns_async_create
I can see that the hostname isn't availble in transport_data->hostAddress.
Going back earlier in the chain, the function IoTHubClient_LL_CreateFromConnectionString() appears to be finding the host name correctly and placing it in config which is passed to initialize_iothub_client() with no error. From there it doesn't get into transport_data->hostAddress.
There is so much pointer work that it is difficult to trace where it is meant to go!
However I have found that in function InitializeTransportHandleData() at the line:
state->hostAddress = STRING_construct_sprintf("%s.%s", upperConfig->iotHubName, upperConfig->iotHubSuffix);
The hostAddress isn't populated. This seems to be because in STRING_construct_sprintf(), STRINGS_C_SPRINTF_BUFFER_SIZE isn't defined.
Should it be?
As a test, I have defined it in the target C/C++ preprocessor symbols and now the host address is appearing in my SocketGetHostByName(). So the define seems to work but is this correct and what other side affects may this cause?
As you have also realized the Azure IoT SDK is quite complex and not so easy to understand or debug.
The function STRING_construct_sprintf will allocate needed memory from heap when STRINGS_C_SPRINTF_BUFFER_SIZE is not defined. So it does not need to be defined explicitly.
I suspect that allocating memory fails in your configuration. You should debug the mentioned function to confirm. Have you tried to increase Heap?
Alternative would be to define that buffer size however I’m not sure what is a good value because this function is used in many different places and having the buffer too small might lead to other failures.
The heap is currently set to 64kB.
If the STRINGS_C_SPRINTF_BUFFER_SIZE is not defined then the arguments for the maxBufSize is set to 0. The function vnsprint then should return the length that the string would be if the buffer was long enough, instead it is returning 0 so then the next part of the function is jumped over and so we don't even get to allocation of memory.
In fact this function is called several times and vnsprintf always returns with a length of 0.
I have done a test with my own function defined as:
int32_t myConstruct_sprintf(const char* format, ...) { size_t maxBufSize = 0; char* buf = NULL; int32_t len; va_list arg_list;
va_start(arg_list, format);
len = vsnprintf(buf, maxBufSize, format, arg_list);
va_end(arg_list);
return len; }
when I call it with:
int32_t length = myConstruct_sprintf("%s.%s", "abc", "xyz");
length is returned as 0, it should be 7.
http://www.keil.com/forum/tips.asp
This is strange. I get the expected 7 as return value when I try your test function.
Which compiler (and version) are you using? What compiler options are you using (target, optimization, other special options, …)?
I have 5.26.2.0.
I tried a clean new project and initially with the default setup I got 7. However when I turned on Use MicroLIB then it failed with 0 returned.
I probably don't need to use MicroLIB, I don't remember my reason for turning it on. But I think the function should still work with it?
Microlib is an alternative to the default C library tailored for deeply embedded applications. It is highly optimized for small code size.
Microlib does not attempt to be an ISO C-compliant library. www.keil.com/.../armlib_chr1358938938181.htm
This might explain behavior of vsnprintf when using NULL pointer and 0 size.
It seems that you should not use Microlib with the Azure SDK.
I know not to use it now.
Thanks for your help in tracing this issue.