static XIO_HANDLE getWebSocketsIOTransport(const char* fully_qualified_name)
{
    XIO_HANDLE result;
    const IO_INTERFACE_DESCRIPTION* io_interface_description = wsio_get_interface_description();
    if (io_interface_description == NULL)
    {
        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_07_013: [ If platform_get_default_tlsio returns NULL getIoTransportProvider shall return NULL. ] */
        LogError("Failure constructing the provider interface");
        result = NULL;
    }
    else
    {
        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_07_012: [ getIoTransportProvider shall return the XIO_HANDLE returns by xio_create. ] */
        WSIO_CONFIG ws_io_config;
        ws_io_config.host = fully_qualified_name;
        ws_io_config.port = 443;
        ws_io_config.protocol_name = "MQTT";
        ws_io_config.relative_path = "/$iothub/websocket";
        ws_io_config.use_ssl = true;
        result = xio_create(io_interface_description, &ws_io_config);
    }
    return result;
}
static PROV_TRANSPORT_IO_INFO* amqp_transport_ws_io(const char* fqdn, SASL_MECHANISM_HANDLE* sasl_mechanism, const HTTP_PROXY_OPTIONS* proxy_info)
{
    PROV_TRANSPORT_IO_INFO* result;
    HTTP_PROXY_IO_CONFIG proxy_config;
    TLSIO_CONFIG tls_io_config;
    WSIO_CONFIG ws_io_config;
    const IO_INTERFACE_DESCRIPTION* ws_io_interface;
    const IO_INTERFACE_DESCRIPTION* tlsio_interface;
    if ((ws_io_interface = wsio_get_interface_description()) == NULL)
    {
        /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_013: [ If any failure is encountered amqp_transport_ws_io shall return NULL ] */
        LogError("wsio_get_interface_description return NULL IO Interface");
        result = NULL;
    }
    else if ((tlsio_interface = platform_get_default_tlsio()) == NULL)
    {
        /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_013: [ If any failure is encountered amqp_transport_ws_io shall return NULL ] */
        LogError("platform_get_default_tlsio return NULL IO Interface");
        result = NULL;
    }
    else
    {
        memset(&tls_io_config, 0, sizeof(TLSIO_CONFIG));

        ws_io_config.hostname = fqdn;
        ws_io_config.port = PROV_AMQP_WS_PORT_NUM;
        ws_io_config.protocol = PROV_AMQP_WS_PROTOCOL_NAME;
        ws_io_config.resource_name = PROV_AMQP_WS_RELATIVE_PATH;
        ws_io_config.underlying_io_interface = tlsio_interface;
        ws_io_config.underlying_io_parameters = &tls_io_config;

        tls_io_config.hostname = fqdn;
        tls_io_config.port = PROV_AMQP_WS_PORT_NUM;
        if (proxy_info != NULL)
        {
            /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_012: [ If proxy_info is not NULL, amqp_transport_ws_io shall construct a HTTP_PROXY_IO_CONFIG object and assign it to TLSIO_CONFIG underlying_io_parameters ] */
            proxy_config.hostname = tls_io_config.hostname;
            proxy_config.port = proxy_info->port;
            proxy_config.proxy_hostname = proxy_info->host_address;
            proxy_config.proxy_port = proxy_info->port;
            proxy_config.username = proxy_info->username;
            proxy_config.password = proxy_info->password;

            tls_io_config.underlying_io_interface = http_proxy_io_get_interface_description();
            tls_io_config.underlying_io_parameters = &proxy_config;
        }
        /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_014: [ On success amqp_transport_ws_io shall return an allocated PROV_TRANSPORT_IO_INFO structure. ] */
        if ((result = (PROV_TRANSPORT_IO_INFO*)malloc(sizeof(PROV_TRANSPORT_IO_INFO))) == NULL)
        {
            /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_013: [ If any failure is encountered amqp_transport_ws_io shall return NULL ] */
            LogError("failure allocating prov_transport info");
            result = NULL;
        }
        else
        {
            memset(result, 0, sizeof(PROV_TRANSPORT_IO_INFO));

            /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_015: [ amqp_transport_ws_io shall allocate a PROV_TRANSPORT_IO_INFO transfer_handle by calling xio_create with the ws_io_interface. ] */
            result->transport_handle = xio_create(ws_io_interface, &ws_io_config);
            if (result->transport_handle == NULL)
            {
                /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_013: [ If any failure is encountered amqp_transport_ws_io shall return NULL ] */
                LogError("failed calling xio_create on underlying io");
                free(result);
                result = NULL;
            }
            else
            {
                if (sasl_mechanism != NULL)
                {
                    const IO_INTERFACE_DESCRIPTION* saslio_interface;
                    SASLCLIENTIO_CONFIG sasl_io_config;
                    sasl_io_config.underlying_io = result->transport_handle;
                    sasl_io_config.sasl_mechanism = *sasl_mechanism;

                    saslio_interface = saslclientio_get_interface_description();
                    if (saslio_interface == NULL)
                    {
                        /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_013: [ If any failure is encountered amqp_transport_ws_io shall return NULL ] */
                        LogError("failed calling xio_create on underlying io");
                        xio_destroy(result->transport_handle);
                        free(result);
                        result = NULL;
                    }
                    else
                    {
                        /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_016: [ amqp_transport_ws_io shall allocate a PROV_TRANSPORT_IO_INFO sasl_handle by calling xio_create with the saslio_interface. ] */
                        result->sasl_handle = xio_create(saslio_interface, &sasl_io_config);
                        if (result->sasl_handle == NULL)
                        {
                            /* Codes_PROV_TRANSPORT_AMQP_WS_CLIENT_07_013: [ If any failure is encountered amqp_transport_ws_io shall return NULL ] */
                            LogError("failed calling xio_create on sasl client interface");
                            xio_destroy(result->transport_handle);
                            free(result);
                            result = NULL;
                        }
                    }
                }
            }
        }
    }
    return result;
}
static XIO_HANDLE getWebSocketsIOTransport(const char* fully_qualified_name, const MQTT_TRANSPORT_PROXY_OPTIONS* mqtt_transport_proxy_options)
{
    XIO_HANDLE result;
    /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_001: [ `getIoTransportProvider` shall obtain the WebSocket IO interface handle by calling `wsio_get_interface_description`. ]*/
    const IO_INTERFACE_DESCRIPTION* io_interface_description = wsio_get_interface_description();
    TLSIO_CONFIG tls_io_config;
    HTTP_PROXY_IO_CONFIG http_proxy_io_config;

    if (io_interface_description == NULL)
    {
        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_07_013: [ If `wsio_get_interface_description` returns NULL `getIoTransportProvider` shall return NULL. ] */
        LogError("Failure constructing the provider interface");
        result = NULL;
    }
    else
    {
        WSIO_CONFIG ws_io_config;

        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_003: [ - `hostname` shall be set to `fully_qualified_name`. ]*/
        ws_io_config.hostname = fully_qualified_name;
        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_004: [ - `port` shall be set to 443. ]*/
        ws_io_config.port = 443;
        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_005: [ - `protocol` shall be set to `MQTT`. ]*/
        ws_io_config.protocol = "MQTT";
        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_006: [ - `resource_name` shall be set to `/$iothub/websocket`. ]*/
        ws_io_config.resource_name = "/$iothub/websocket";
        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_007: [ - `underlying_io_interface` shall be set to the TLS IO interface description. ]*/
        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_009: [ `getIoTransportProvider` shall obtain the TLS IO interface handle by calling `platform_get_default_tlsio`. ]*/
        ws_io_config.underlying_io_interface = platform_get_default_tlsio();

        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_029: [ If `platform_get_default_tlsio` returns NULL, NULL shall be set in the WebSocket IO parameters structure for the interface description and parameters. ]*/
        if (ws_io_config.underlying_io_interface == NULL)
        {
            ws_io_config.underlying_io_parameters = NULL;
        }
        else
        {
            /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_008: [ - `underlying_io_parameters` shall be set to the TLS IO arguments. ]*/
            /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_010: [ The TLS IO parameters shall be a TLSIO_CONFIG structure filled as below: ]*/
            ws_io_config.underlying_io_parameters = &tls_io_config;

            /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_011: [ - `hostname` shall be set to `fully_qualified_name`. ]*/
            tls_io_config.hostname = fully_qualified_name;
            /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_012: [ - `port` shall be set to 443. ]*/
            tls_io_config.port = 443;

            if (mqtt_transport_proxy_options != NULL)
            {
                /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_015: [ - If `mqtt_transport_proxy_options` is not NULL, `underlying_io_interface` shall be set to the HTTP proxy IO interface description. ]*/
                /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_022: [ `getIoTransportProvider` shall obtain the HTTP proxy IO interface handle by calling `http_proxy_io_get_interface_description`. ]*/
                tls_io_config.underlying_io_interface = http_proxy_io_get_interface_description();

                /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_028: [ If `http_proxy_io_get_interface_description` returns NULL, NULL shall be set in the TLS IO parameters structure for the interface description and parameters. ]*/
                if (tls_io_config.underlying_io_interface == NULL)
                {
                    tls_io_config.underlying_io_parameters = NULL;
                }
                else
                {
                    /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_016: [ - If `mqtt_transport_proxy_options` is not NULL `underlying_io_parameters` shall be set to the HTTP proxy IO arguments. ]*/
                    tls_io_config.underlying_io_parameters = &http_proxy_io_config;

                    /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_023: [ The HTTP proxy IO arguments shall be an `HTTP_PROXY_IO_CONFIG` structure, filled as below: ]*/
                    /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_026: [ - `proxy_hostname`, `proxy_port`, `username` and `password` shall be copied from the `mqtt_transport_proxy_options` argument. ]*/
                    http_proxy_io_config.proxy_hostname = mqtt_transport_proxy_options->host_address;
                    http_proxy_io_config.proxy_port = mqtt_transport_proxy_options->port;
                    http_proxy_io_config.username = mqtt_transport_proxy_options->username;
                    http_proxy_io_config.password = mqtt_transport_proxy_options->password;
                    /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_024: [ - `hostname` shall be set to `fully_qualified_name`. ]*/
                    http_proxy_io_config.hostname = fully_qualified_name;
                    /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_025: [ - `port` shall be set to 443. ]*/
                    http_proxy_io_config.port = 443;
                }
            }
            else
            {
                /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_013: [ - If `mqtt_transport_proxy_options` is NULL, `underlying_io_interface` shall be set to NULL ]*/
                tls_io_config.underlying_io_interface = NULL;
                /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_014: [ - If `mqtt_transport_proxy_options` is NULL `underlying_io_parameters` shall be set to NULL. ]*/
                tls_io_config.underlying_io_parameters = NULL;
            }
        }

        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_07_012: [ `getIoTransportProvider` shall return the `XIO_HANDLE` returned by `xio_create`. ] */
        /* Codes_SRS_IOTHUB_MQTT_WEBSOCKET_TRANSPORT_01_002: [ `getIoTransportProvider` shall call `xio_create` while passing the WebSocket IO interface description to it and the WebSocket configuration as a WSIO_CONFIG structure, filled as below ]*/
        result = xio_create(io_interface_description, &ws_io_config);
    }
    return result;
}
static XIO_HANDLE getWebSocketsIOTransport(const char* fqdn, const AMQP_TRANSPORT_PROXY_OPTIONS* amqp_transport_proxy_options)
{
    WSIO_CONFIG ws_io_config;
    TLSIO_CONFIG tls_io_config;
    HTTP_PROXY_IO_CONFIG http_proxy_io_config;
    /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_001: [ `getIoTransportProvider` shall obtain the WebSocket IO interface handle by calling `wsio_get_interface_description`. ]*/
    const IO_INTERFACE_DESCRIPTION* io_interface_description = wsio_get_interface_description();
    XIO_HANDLE result;

    if (io_interface_description == NULL)
    {
        LogError("Failure constructing the provider interface");
        /* Codes_SRS_IoTHubTransportAMQP_WS_09_003: [If `io_interface_description` is NULL getWebSocketsIOTransport shall return NULL.] */
        result = NULL;
    }
    else
    {
        /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_003: [ - `hostname` shall be set to `fqdn`. ]*/
        ws_io_config.hostname = fqdn;
        /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_004: [ - `port` shall be set to 443. ]*/
        ws_io_config.port = DEFAULT_WS_PORT;
        /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_005: [ - `protocol` shall be set to `AMQPWSB10`. ]*/
        ws_io_config.protocol = DEFAULT_WS_PROTOCOL_NAME;
        /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_006: [ - `resource_name` shall be set to `/$iothub/websocket`. ]*/
        ws_io_config.resource_name = DEFAULT_WS_RELATIVE_PATH;
        /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_007: [ - `underlying_io_interface` shall be set to the TLS IO interface description. ]*/
        /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_009: [ `getIoTransportProvider` shall obtain the TLS IO interface handle by calling `platform_get_default_tlsio`. ]*/
        ws_io_config.underlying_io_interface = platform_get_default_tlsio();

        /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_029: [ If `platform_get_default_tlsio` returns NULL, NULL shall be set in the WebSocket IO parameters structure for the interface description and parameters. ]*/
        if (ws_io_config.underlying_io_interface == NULL)
        {
            ws_io_config.underlying_io_parameters = NULL;
        }
        else
        {
            /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_008: [ - `underlying_io_parameters` shall be set to the TLS IO arguments. ]*/
            ws_io_config.underlying_io_parameters = &tls_io_config;

            /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_010: [ The TLS IO parameters shall be a `TLSIO_CONFIG` structure filled as below: ]*/
            /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_011: [ - `hostname` shall be set to `fqdn`. ]*/
            tls_io_config.hostname = fqdn;
            /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_012: [ - `port` shall be set to 443. ]*/
            tls_io_config.port = DEFAULT_WS_PORT;

            if (amqp_transport_proxy_options != NULL)
            {
                /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_015: [ - If `amqp_transport_proxy_options` is not NULL, `underlying_io_interface` shall be set to the HTTP proxy IO interface description. ]*/
                /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_022: [ `getIoTransportProvider` shall obtain the HTTP proxy IO interface handle by calling `http_proxy_io_get_interface_description`. ]*/
                tls_io_config.underlying_io_interface = http_proxy_io_get_interface_description();

                /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_028: [ If `http_proxy_io_get_interface_description` returns NULL, NULL shall be set in the TLS IO parameters structure for the interface description and parameters. ]*/
                if (tls_io_config.underlying_io_interface == NULL)
                {
                    tls_io_config.underlying_io_parameters = NULL;
                }
                else
                {
                    /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_016: [ - If `amqp_transport_proxy_options` is not NULL `underlying_io_parameters` shall be set to the HTTP proxy IO arguments. ]*/
                    tls_io_config.underlying_io_parameters = &http_proxy_io_config;

                    /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_023: [ The HTTP proxy IO arguments shall be an `HTTP_PROXY_IO_CONFIG` structure, filled as below: ]*/
                    /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_026: [ - `proxy_hostname`, `proxy_port`, `username` and `password` shall be copied from the `mqtt_transport_proxy_options` argument. ]*/
                    http_proxy_io_config.proxy_hostname = amqp_transport_proxy_options->host_address;
                    http_proxy_io_config.proxy_port = amqp_transport_proxy_options->port;
                    http_proxy_io_config.username = amqp_transport_proxy_options->username;
                    http_proxy_io_config.password = amqp_transport_proxy_options->password;
                    /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_024: [ - `hostname` shall be set to `fully_qualified_name`. ]*/
                    http_proxy_io_config.hostname = fqdn;
                    /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_025: [ - `port` shall be set to 443. ]*/
                    http_proxy_io_config.port = DEFAULT_WS_PORT;
                }
            }
            else
            {
                /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_013: [ - If `amqp_transport_proxy_options` is NULL, `underlying_io_interface` shall be set to NULL. ]*/
                tls_io_config.underlying_io_interface = NULL;
                /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_014: [ - If `amqp_transport_proxy_options` is NULL `underlying_io_parameters` shall be set to NULL. ]*/
                tls_io_config.underlying_io_parameters = NULL;
            }
        }

        /* Codes_SRS_IoTHubTransportAMQP_WS_09_004: [getWebSocketsIOTransport shall return the XIO_HANDLE created using xio_create().] */
        /* Codes_SRS_IOTHUBTRANSPORTAMQP_WS_01_002: [ `getIoTransportProvider` shall call `xio_create` while passing the WebSocket IO interface description to it and the WebSocket configuration as a WSIO_CONFIG structure, filled as below: ]*/
        result = xio_create(io_interface_description, &ws_io_config);
    }

    return result;
}