extern TRANSPORT_HANDLE IoTHubTransportMqtt_Create(const IOTHUBTRANSPORT_CONFIG* config)
{
    PMQTTTRANSPORT_HANDLE_DATA result;
    size_t deviceIdSize;
    
    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_001: [If parameter config is NULL then IoTHubTransportMqtt_Create shall return NULL.] */
    if (config == NULL)
    {
        LogError("Invalid Argument: Config Parameter is NULL.\r\n");
        result = NULL;
    }
    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_002: [If the parameter config's variables upperConfig or waitingToSend are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [If the upperConfig's variables deviceId, deviceKey, iotHubName, protocol, or iotHubSuffix are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
    else if (config->upperConfig == NULL || config->upperConfig->protocol == NULL || config->upperConfig->deviceId == NULL || config->upperConfig->deviceKey == NULL ||
        config->upperConfig->iotHubName == NULL || config->upperConfig->iotHubSuffix == NULL)
    {
        LogError("Invalid Argument: upperConfig structure contains an invalid parameter\r\n");
        result = NULL;
    }
    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_002: [If the parameter config's variables upperConfig or waitingToSend are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
    else if (config->waitingToSend == NULL)
    {
        LogError("Invalid Argument: waitingToSend is NULL)\r\n");
        result = NULL;
    }
    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_006: [If the upperConfig's variables deviceId is an empty strings or length is greater then 128 then IoTHubTransportMqtt_Create shall return NULL.] */
    else if ( ( (deviceIdSize = strlen(config->upperConfig->deviceId)) > 128U) || (deviceIdSize == 0) )
    {
        LogError("Invalid Argument: DeviceId is of an invalid size\r\n");
        result = NULL;
    }
    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [If the upperConfig's variables deviceId, deviceKey, iotHubName, protocol, or iotHubSuffix are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
    else if (strlen(config->upperConfig->deviceKey) == 0)
    {
        LogError("Invalid Argument: deviceKey is empty\r\n");
        result = NULL;
    }
    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [If the upperConfig's variables deviceId, deviceKey, iotHubName, protocol, or iotHubSuffix are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
    else if (strlen(config->upperConfig->iotHubName) == 0)
    {
        LogError("Invalid Argument: iotHubName is empty\r\n");
        result = NULL;
    }
    else
    {
        result = InitializeTransportHandleData(config->upperConfig, config->waitingToSend);
        if (result != NULL)
        {
            g_msgTickCounter = tickcounter_create();
        }
    }
    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_009: [If any error is encountered then IoTHubTransportMqtt_Create shall return NULL.] */
    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_011: [On Success IoTHubTransportMqtt_Create shall return a non-NULL value.] */
    return result;
}
示例#2
0
文件: main.c 项目: MZDN/azure-uamqp-c
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;
        SASL_PLAIN_CONFIG sasl_plain_config = { EH_KEY_NAME, EH_KEY, NULL };
        TLSIO_CONFIG tls_io_config = { EH_HOST, 5671 };
        const IO_INTERFACE_DESCRIPTION* tlsio_interface;
        SASLCLIENTIO_CONFIG sasl_io_config;
        AMQP_VALUE source;
        AMQP_VALUE target;

        size_t last_memory_used = 0;
        SASL_MECHANISM_HANDLE sasl_mechanism_handle;
        XIO_HANDLE tls_io;
        unsigned char hello[] = { 'H', 'e', 'l', 'l', 'o' };
        BINARY_DATA binary_data;

        gballoc_init();

        /* create SASL PLAIN handler */
        sasl_mechanism_handle = saslmechanism_create(saslplain_get_interface(), &sasl_plain_config);

        /* 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);

        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_unsettled);
        (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));
                    }
                }
            }
        }
        else
        {
            message_destroy(message);
        }

        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;
}
IOTHUB_CLIENT_LL_HANDLE IoTHubClient_LL_CreateWithTransport(const IOTHUB_CLIENT_DEVICE_CONFIG * config)
{
    IOTHUB_CLIENT_LL_HANDLE result;
    /*Codes_SRS_IOTHUBCLIENT_LL_17_001: [IoTHubClient_LL_CreateWithTransport shall return NULL if config parameter is NULL, or protocol field is NULL or transportHandle is NULL.]*/
    if (
        (config == NULL) ||
        (config->protocol == NULL) ||
        (config->transportHandle == NULL)
        )
    {
        result = NULL;
        LogError("invalid configuration (NULL detected)");
    }
    else
    {
        /*Codes_SRS_IOTHUBCLIENT_LL_17_002: [IoTHubClient_LL_CreateWithTransport shall allocate data for the IOTHUB_CLIENT_LL_HANDLE.]*/
        IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)malloc(sizeof(IOTHUB_CLIENT_LL_HANDLE_DATA));
        if (handleData == NULL)
        {
            /*Codes_SRS_IOTHUBCLIENT_LL_17_003: [If allocation fails, the function shall fail and return NULL.] */
            LogError("malloc failed");
            result = NULL;
        }
        else
        {
            handleData->uploadToBlobHandle = NULL;
            /*Codes_SRS_IOTHUBCLIENT_LL_02_047: [ IoTHubClient_LL_CreateWithTransport shall create a TICK_COUNTER_HANDLE. ]*/
            if ((handleData->tickCounter = tickcounter_create()) == NULL)
            {
                /*Codes_SRS_IOTHUBCLIENT_LL_02_048: [ If creating the handle fails, then IoTHubClient_LL_CreateWithTransport shall fail and return NULL ]*/
                LogError("unable to get a tickcounter");
                free(handleData);
                result = NULL;
            }
            else
            {
                /*Codes_SRS_IOTHUBCLIENT_LL_17_004: [IoTHubClient_LL_CreateWithTransport shall initialize a new DLIST (further called "waitingToSend") containing records with fields of the following types: IOTHUB_MESSAGE_HANDLE, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, void*.]*/
                DList_InitializeListHead(&(handleData->waitingToSend));
                setTransportProtocol(handleData, (TRANSPORT_PROVIDER*)config->protocol());
                handleData->messageCallback = NULL;
                handleData->messageUserContextCallback = NULL;
                handleData->lastMessageReceiveTime = INDEFINITE_TIME;
                handleData->transportHandle = config->transportHandle;


                IOTHUB_DEVICE_CONFIG deviceConfig;

                deviceConfig.deviceId = config->deviceId;
                deviceConfig.deviceKey = config->deviceKey;
                deviceConfig.deviceSasToken = config->deviceSasToken;

                /*Codes_SRS_IOTHUBCLIENT_LL_17_006: [IoTHubClient_LL_CreateWithTransport shall call the transport _Register function with the IOTHUB_DEVICE_CONFIG populated structure and waitingToSend list.]*/
                if ((handleData->deviceHandle = handleData->IoTHubTransport_Register(config->transportHandle, &deviceConfig, handleData, &(handleData->waitingToSend))) == NULL)
                {
                    /*Codes_SRS_IOTHUBCLIENT_LL_17_007: [If the _Register function fails, this function shall fail and return NULL.]*/
                    LogError("Registering device in transport failed");

                    tickcounter_destroy(handleData->tickCounter);
                    free(handleData);
                    result = NULL;
                }
                else
                {
                    /*Codes_SRS_IOTHUBCLIENT_LL_17_005: [IoTHubClient_LL_CreateWithTransport shall save the transport handle and mark this transport as shared.]*/
                    handleData->isSharedTransport = true;
                    /*Codes_SRS_IOTHUBCLIENT_LL_02_042: [ By default, messages shall not timeout. ]*/
                    handleData->currentMessageTimeout = 0;
                    result = handleData;
                }
            }
        }
    }

    return result;
}
IOTHUB_CLIENT_LL_HANDLE IoTHubClient_LL_Create(const IOTHUB_CLIENT_CONFIG* config)
{
    IOTHUB_CLIENT_LL_HANDLE result;
    /*Codes_SRS_IOTHUBCLIENT_LL_02_001: [IoTHubClient_LL_Create shall return NULL if config parameter is NULL or protocol field is NULL.]*/
    if( 
        (config == NULL) ||
        (config->protocol == NULL)
        )
    {
        result = NULL;
        LogError("invalid configuration (NULL detected)");
    }
    else
    {
        IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)malloc(sizeof(IOTHUB_CLIENT_LL_HANDLE_DATA));
        if (handleData == NULL)
        {
            LogError("malloc failed");
            result = NULL;
        }
        else
        {
            /*Codes_SRS_IOTHUBCLIENT_LL_02_094: [ IoTHubClient_LL_Create shall create a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE from IOTHUB_CLIENT_CONFIG. ]*/
            /*Codes_SRS_IOTHUBCLIENT_LL_02_092: [ IoTHubClient_LL_CreateFromConnectionString shall create a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE from IOTHUB_CLIENT_CONFIG. ]*/
            handleData->uploadToBlobHandle = IoTHubClient_LL_UploadToBlob_Create(config);
            if (handleData->uploadToBlobHandle == NULL)
            {
                /*Codes_SRS_IOTHUBCLIENT_LL_02_093: [ If creating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_CreateFromConnectionString shall fail and return NULL. ]*/
                /*Codes_SRS_IOTHUBCLIENT_LL_02_095: [ If creating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_Create shall fail and return NULL. ]*/
                LogError("unable to IoTHubClient_LL_UploadToBlob_Create");
                free(handleData);
                result = NULL;
            }
            else
            {
                /*Codes_SRS_IOTHUBCLIENT_LL_02_045: [ Otherwise IoTHubClient_LL_Create shall create a new TICK_COUNTER_HANDLE ]*/
                if ((handleData->tickCounter = tickcounter_create()) == NULL)
                {
                    /*Codes_SRS_IOTHUBCLIENT_LL_02_046: [ If creating the TICK_COUNTER_HANDLE fails then IoTHubClient_LL_Create shall fail and return NULL. ]*/
                    IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle);
                    LogError("unable to get a tickcounter");
                    free(handleData);
                    result = NULL;
                }
                else
                {
                    /*Codes_SRS_IOTHUBCLIENT_LL_02_004: [Otherwise IoTHubClient_LL_Create shall initialize a new DLIST (further called "waitingToSend") containing records with fields of the following types: IOTHUB_MESSAGE_HANDLE, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, void*.]*/
                    IOTHUBTRANSPORT_CONFIG lowerLayerConfig;
                    DList_InitializeListHead(&(handleData->waitingToSend));
                    setTransportProtocol(handleData, (TRANSPORT_PROVIDER*)config->protocol());
                    handleData->messageCallback = NULL;
                    handleData->messageUserContextCallback = NULL;
                    handleData->lastMessageReceiveTime = INDEFINITE_TIME;
                    /*Codes_SRS_IOTHUBCLIENT_LL_02_006: [IoTHubClient_LL_Create shall populate a structure of type IOTHUBTRANSPORT_CONFIG with the information from config parameter and the previous DLIST and shall pass that to the underlying layer _Create function.]*/
                    lowerLayerConfig.upperConfig = config;
                    lowerLayerConfig.waitingToSend = &(handleData->waitingToSend);
                    /*Codes_SRS_IOTHUBCLIENT_LL_02_007: [If the underlaying layer _Create function fails them IoTHubClient_LL_Create shall fail and return NULL.] */
                    if ((handleData->transportHandle = handleData->IoTHubTransport_Create(&lowerLayerConfig)) == NULL)
                    {
                        LogError("underlying transport failed");
                        IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle);
                        tickcounter_destroy(handleData->tickCounter);
                        free(handleData);
                        result = NULL;
                    }
                    else
                    {
                        IOTHUB_DEVICE_CONFIG deviceConfig;

                        deviceConfig.deviceId = config->deviceId;
                        deviceConfig.deviceKey = config->deviceKey;
                        deviceConfig.deviceSasToken = config->deviceSasToken;

                        /*Codes_SRS_IOTHUBCLIENT_LL_17_008: [IoTHubClient_LL_Create shall call the transport _Register function with a populated structure of type IOTHUB_DEVICE_CONFIG and waitingToSend list.] */
                        if ((handleData->deviceHandle = handleData->IoTHubTransport_Register(handleData->transportHandle, &deviceConfig, handleData, &(handleData->waitingToSend))) == NULL)
                        {
                            /*Codes_SRS_IOTHUBCLIENT_LL_17_009: [If the _Register function fails, this function shall fail and return NULL.]*/
                            LogError("Registering device in transport failed");
                            handleData->IoTHubTransport_Destroy(handleData->transportHandle);
                            IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle);
                            tickcounter_destroy(handleData->tickCounter);
                            free(handleData);
                            result = NULL;
                        }
                        else
                        {
                            /*Codes_SRS_IOTHUBCLIENT_LL_02_008: [Otherwise, IoTHubClient_LL_Create shall succeed and return a non-NULL handle.] */
                            handleData->isSharedTransport = false;
                            /*Codes_SRS_IOTHUBCLIENT_LL_02_042: [ By default, messages shall not timeout. ]*/
                            handleData->currentMessageTimeout = 0;
                            result = handleData;
                        }
                    }
                }
            }
        }
    }

    return result;
}
示例#5
0
文件: main.c 项目: MZDN/azure-uamqp-c
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;
}
IOTHUB_CLIENT_LL_HANDLE IoTHubClient_LL_CreateWithTransport(const IOTHUB_CLIENT_DEVICE_CONFIG * config)
{
    IOTHUB_CLIENT_LL_HANDLE result;
    /*Codes_SRS_IOTHUBCLIENT_LL_17_001: [IoTHubClient_LL_CreateWithTransport shall return NULL if config parameter is NULL, or protocol field is NULL or transportHandle is NULL.]*/
    if (
        (config == NULL) ||
        (config->protocol == NULL) ||
        (config->transportHandle == NULL) ||
        /*Codes_SRS_IOTHUBCLIENT_LL_02_098: [ IoTHubClient_LL_CreateWithTransport shall fail and return NULL if both config->deviceKey AND config->deviceSasToken are NULL. ]*/
        ((config->deviceKey == NULL) && (config->deviceSasToken == NULL))
        )
    {
        result = NULL;
        LogError("invalid configuration (NULL detected)");
    }
    else
    {
        /*Codes_SRS_IOTHUBCLIENT_LL_17_002: [IoTHubClient_LL_CreateWithTransport shall allocate data for the IOTHUB_CLIENT_LL_HANDLE.]*/
        IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)malloc(sizeof(IOTHUB_CLIENT_LL_HANDLE_DATA));
        if (handleData == NULL)
        {
            /*Codes_SRS_IOTHUBCLIENT_LL_17_003: [If allocation fails, the function shall fail and return NULL.] */
            LogError("malloc failed");
            result = NULL;
        }
        else
        {
            handleData->transportHandle = config->transportHandle;
            setTransportProtocol(handleData, (TRANSPORT_PROVIDER*)config->protocol());

#ifndef DONT_USE_UPLOADTOBLOB
            const char* hostname = STRING_c_str(handleData->IoTHubTransport_GetHostname(handleData->transportHandle));
            /*Codes_SRS_IOTHUBCLIENT_LL_02_096: [ IoTHubClient_LL_CreateWithTransport shall create the data structures needed to instantiate a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE. ]*/
            /*the first '.' says where the iothubname finishes*/
            const char* whereIsDot = strchr(hostname, '.');
            if (whereIsDot == NULL)
            {
                /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_CreateWithTransport shall fail and return NULL. ]*/
                LogError("unable to determine the IoTHub name");
                free(handleData);
                result = NULL;
            }
            else
            {
                /*Codes_SRS_IOTHUBCLIENT_LL_02_096: [ IoTHubClient_LL_CreateWithTransport shall create the data structures needed to instantiate a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE. ]*/
                char* IoTHubName = malloc(whereIsDot - hostname + 1);
                if (IoTHubName == NULL)
                {
                    /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_CreateWithTransport shall fail and return NULL. ]*/
                    LogError("unable to malloc");
                    free(handleData);
                    result = NULL;
                }
                else
                {
                    const char* IotHubSuffix = whereIsDot + 1;
                    memcpy(IoTHubName, hostname, whereIsDot - hostname);
                    IoTHubName[whereIsDot - hostname ] = '\0';
                    
                    IOTHUB_CLIENT_CONFIG temp;
                    temp.deviceId = config->deviceId;
                    temp.deviceKey = config->deviceKey;
                    temp.deviceSasToken = config->deviceSasToken;
                    temp.iotHubName = IoTHubName;
                    temp.iotHubSuffix = IotHubSuffix;
                    temp.protocol = NULL; /*irrelevant to IoTHubClient_LL_UploadToBlob*/
                    temp.protocolGatewayHostName = NULL; /*irrelevant to IoTHubClient_LL_UploadToBlob*/

                    /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_CreateWithTransport shall fail and return NULL. ]*/
                    handleData->uploadToBlobHandle = IoTHubClient_LL_UploadToBlob_Create(&temp);
                    if (handleData->uploadToBlobHandle == NULL)
                    {
                        /*Codes_SRS_IOTHUBCLIENT_LL_02_096: [ IoTHubClient_LL_CreateWithTransport shall create the data structures needed to instantiate a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE. ]*/
                        LogError("unable to IoTHubClient_LL_UploadToBlob_Create");
                        free(handleData);
                        result = NULL;
                    }
                    else
#endif
                    {
                        /*Codes_SRS_IOTHUBCLIENT_LL_02_047: [ IoTHubClient_LL_CreateWithTransport shall create a TICK_COUNTER_HANDLE. ]*/
                        if ((handleData->tickCounter = tickcounter_create()) == NULL)
                        {
                            /*Codes_SRS_IOTHUBCLIENT_LL_02_048: [ If creating the handle fails, then IoTHubClient_LL_CreateWithTransport shall fail and return NULL ]*/
                            LogError("unable to get a tickcounter");
#ifndef DONT_USE_UPLOADTOBLOB
                            IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle);
#endif
                            free(handleData);
                            result = NULL;
                        }
                        else
                        {
                            /*Codes_SRS_IOTHUBCLIENT_LL_17_004: [IoTHubClient_LL_CreateWithTransport shall initialize a new DLIST (further called "waitingToSend") containing records with fields of the following types: IOTHUB_MESSAGE_HANDLE, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, void*.]*/
                            DList_InitializeListHead(&(handleData->waitingToSend));
                            
                            handleData->messageCallback = NULL;
                            handleData->messageUserContextCallback = NULL;
                            handleData->lastMessageReceiveTime = INDEFINITE_TIME;
                            

                            IOTHUB_DEVICE_CONFIG deviceConfig;

                            deviceConfig.deviceId = config->deviceId;
                            deviceConfig.deviceKey = config->deviceKey;
                            deviceConfig.deviceSasToken = config->deviceSasToken;

                            /*Codes_SRS_IOTHUBCLIENT_LL_17_006: [IoTHubClient_LL_CreateWithTransport shall call the transport _Register function with the IOTHUB_DEVICE_CONFIG populated structure and waitingToSend list.]*/
                            if ((handleData->deviceHandle = handleData->IoTHubTransport_Register(config->transportHandle, &deviceConfig, handleData, &(handleData->waitingToSend))) == NULL)
                            {
                                /*Codes_SRS_IOTHUBCLIENT_LL_17_007: [If the _Register function fails, this function shall fail and return NULL.]*/
                                LogError("Registering device in transport failed");
#ifndef DONT_USE_UPLOADTOBLOB
                                IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle);
#endif
                                tickcounter_destroy(handleData->tickCounter);
                                free(handleData);
                                result = NULL;
                            }
                            else
                            {
                                /*Codes_SRS_IOTHUBCLIENT_LL_17_005: [IoTHubClient_LL_CreateWithTransport shall save the transport handle and mark this transport as shared.]*/
                                handleData->isSharedTransport = true;
                                /*Codes_SRS_IOTHUBCLIENT_LL_02_042: [ By default, messages shall not timeout. ]*/
                                handleData->currentMessageTimeout = 0;
                                result = handleData;
                            }
                        }
                    }
#ifndef DONT_USE_UPLOADTOBLOB
                    free(IoTHubName);
                }
            }
#endif
        }
    }

    return result;
}