Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deadlock between IoTHubClient_UploadToBlobAsync and IoTHubClient_SendEventAsync when used with DeviceMethodCallback #82

Closed
N6UDP opened this issue Mar 1, 2017 · 2 comments
Assignees
Labels

Comments

@N6UDP
Copy link
Member

N6UDP commented Mar 1, 2017

I seem to be getting a deadlock between IoTHubClient_UploadToBlobAsync and IoTHubClient_SendEventAsync when used with DeviceMethodCallback. Platform is MIPS Linux. As requested in #26 here is a repro:

#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/platform.h"
#include "iothub_client.h"
#include "iothub_message.h"
#include "iothubtransportmqtt.h"

static int callbackCounter;
IOTHUB_CLIENT_HANDLE iotHubClientHandle;
typedef struct EVENT_INSTANCE_TAG
{
    IOTHUB_MESSAGE_HANDLE messageHandle;
    size_t messageTrackingId;  // For tracking the messages within the user callback.
} EVENT_INSTANCE;

void takepicture(void);
static int DeviceMethodCallback(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* resp_size, void* userContextCallback)
{
    (void)userContextCallback;
    int status = 200;
    printf("\r\nDevice Method called\r\n");
    printf("Device Method name:    %s\r\n", method_name);
    printf("Device Method payload: %.*s\r\n", (int)size, (const char*)payload);
if(strcmp(method_name,"takepicture")==0){
        takepicture();
    }
  char* RESPONSE_STRING = "{ \"Response\": \"Nothing\" }";
    printf("\r\nResponse status: %d\r\n", status);
    printf("Response payload: %s\r\n\r\n", RESPONSE_STRING);

    *resp_size = strlen(RESPONSE_STRING);
    if ((*response = malloc(*resp_size)) == NULL)
    {
        status = -1;
    }
    else
    {
        (void)memcpy(*response, RESPONSE_STRING, *resp_size);
    }

    return status;
}
static void SendConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback)
{
    EVENT_INSTANCE* eventInstance = (EVENT_INSTANCE*)userContextCallback;
    (void)printf("Confirmation[%d] received for message tracking id = %zu with result = %s\r\n", callbackCounter, eventInstance->messageTrackingId, ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result));
    callbackCounter++;
    IoTHubMessage_Destroy(eventInstance->messageHandle);
}
void takepicture(void){
 long length = 0;
    unsigned char* imagebuffer = NULL;
    FILE* fo = fopen("/tmp/snap.jpg", "r");

    if(fo)
    {
        fseek(fo, 0, SEEK_END);
        length = ftell(fo);
        fseek(fo, 0, SEEK_SET);

        if(length)
        {
            imagebuffer = (unsigned char *)malloc(length*sizeof(unsigned char));
            fread(imagebuffer, length, 1, fo);
            printf("its %ld long\n",length);
            if (IoTHubClient_UploadToBlobAsync(iotHubClientHandle, "file.jpg", (const unsigned char*)imagebuffer, length, NULL, NULL) != IOTHUB_CLIENT_OK)
            {
                printf("Image failed to upload\n");
            }
            else
            {
                printf("Image has been created\n");
            }
        }
        fclose(fo);
        free(imagebuffer);
    }
}
void loop(void)
{

    EVENT_INSTANCE messages[MESSAGE_COUNT];
    int receiveContext = 0;


    callbackCounter = 0;

    if (platform_init() != 0)
    {
        fprintf(stderr,"Failed to initialize the platform.\r\n");
        exit(1);
    }
    if ((iotHubClientHandle = IoTHubClient_CreateFromConnectionString("YOURSTRINGHERE", MQTT_Protocol)) == NULL)
    {
        (void)fprintf(stderr,"ERROR: iotHubClientHandle is NULL!\r\n");
        exit(1);
    }
    bool traceOn = true;
    IoTHubClient_SetOption(iotHubClientHandle, "logtrace", &traceOn);


    if (IoTHubClient_SetDeviceMethodCallback(iotHubClientHandle, DeviceMethodCallback, &receiveContext) != IOTHUB_CLIENT_OK)
    {
        (void)fprintf(stderr,"ERROR: IoTHubClient_SetMessageCallback..........FAILED!\r\n");
        exit(1);
    }

    (void)printf("IoTHubClient_SetMessageCallback...successful.\r\n");

    /* Now that we are ready to receive commands, let's send some messages */
    size_t iterator = 0;
    do
    {
    
         const char* msgText = "test";

             
                if ((messages[iterator].messageHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)msgText, strlen(msgText))) == NULL)
                {
                    (void)fprintf(stderr,"ERROR: iotHubMessageHandle is NULL!\r\n");
          exit(1);
                }
                else
                {
                    MAP_HANDLE propMap;

                    messages[iterator].messageTrackingId = iterator;

                    propMap = IoTHubMessage_Properties(messages[iterator].messageHandle);
                    (void)sprintf_s(propText, sizeof(propText), "PropMsg_%zu", iterator);
                    if (Map_AddOrUpdate(propMap, "PropName", propText) != MAP_OK)
                    {
                        (void)fprintf(stderr,"ERROR: Map_AddOrUpdate Failed!\r\n");
                    }

                    if (IoTHubClient_SendEventAsync(iotHubClientHandle, messages[iterator].messageHandle, SendConfirmationCallback, &messages[iterator]) != IOTHUB_CLIENT_OK)
                    {
                        (void)fprintf(stderr,"ERROR: IoTHubClient_SendEventAsync..........FAILED!\r\n");
                        exit(1);
                    }
                    else
                    {
                        (void)printf("IoTHubClient_SendEventAsync accepted message [%zu] for transmission to IoT Hub.\r\n", iterator);
                    }

                }
                }else {(void)printf("ERROR: NoDataFromGetInfo..........FAILED!\r\n");}
            } 
        }
        if(iterator % 20 == 0) {
            takepicture(); // This works oddly enough
        }
        ThreadAPI_Sleep(20000);
iterator++;

    } while (true);

    IoTHubClient_Destroy(iotHubClientHandle);

    platform_deinit();

}
int main(void)
{
    loop();
    return 0;
}
@mhshami01
Copy link
Contributor

Hello @N6UDP

Thank you for your submission. I am investigating your report.

Best Regards,
Haitham Shami

@mhshami01
Copy link
Contributor

Hello @N6UDP,

I have recently checked in master branch fixes that would allow IoTHubClient_UploadToBlobAsync to be called from inside a device_method_callback function.

I am hoping this unblocks you. If you still encounter issues, please reply here.

Best Regards,
Haitham Shami

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants