本文的常见问题与Link SDK的C语言版本相关,通用性的常见问题请参见本产品的“常见问题”章节。
make menuconfig提示126错误码
用户使用make menuconfig对SDK进行裁剪时,提示126的错误。
错误原因:Ubuntu的版本过低,导致调用make menuconfig出错
解决办法:将Ubuntu进行升级到16.04及以上
如何编译SDK能够减小二进制尺寸
请注意以下的编译选项在 CFLAGS
中能够起到的作用
选项 | 说明 |
---|---|
-Os |
尺寸优化选项, GNU系列的工具链一般都会支持 |
-g3 |
调试附加选项, 如果不需要使用gdb 调试, 可以去掉来减小尺寸
|
--coverage |
覆盖率统计选项, 如果不需要用lcov 统计代码覆盖率, 可以去掉来减小尺寸
|
-ffunction-sections |
将函数分段摆放, 不被使用的函数将不进入最终的二进制, 加上此选项可减小最终的可执行程序/镜像大小 |
-fdata-sections |
将数据分段摆放, 不被使用的变量将不进入最终的二进制, 加上此选项可减小最终的可执行程序/镜像大小 |
-Wl,--gc-sections |
链接的时候让未使用的符号不进入最终的二进制, 减小尺寸, 本选项需要和上面的2个选项组合使用 |
同时如下的功能开关可以考虑关闭, 以减小尺寸
开关 | 说明 |
---|---|
FEATURE_AWSS_SUPPORT_ROUTER |
配网中的路由器配网模式, 一般可以直接关闭, 以减小尺寸 |
FEATURE_AWSS_SUPPORT_PHONEASAP |
配网中的手机热点配网模式, 一般不使用这种模式的时候也可以关闭, 以减小尺寸 |
如何解决嵌入式平台上 strtod()
不工作问题
在有些嵌入式平台上, 由于C库被定制, 标准的C99库函数 strtod()
可能不工作甚至引起崩溃和死机, 可通过setlocale(LC_ALL, "C");
的方式使能C库能力全集来解决。
SDK几个库文件的编译时的链接顺序
当编译应用程序时链接SDK的顺序,请务必保持使用
-liot_sdk -liot_hal -liot_tls
这样的顺序来链接SDK提供的几个分库, 因为写在后面的都是对前面库的支撑
对于移植到Linux上使用的情况, 还需要以
-liot_sdk -liot_hal -liot_tls -lpthread -lrt
的方式来书写, 这是因为SDK在Linux下的HAL参考实现使用了pthread库和librt实时库
例如, 使用 dlopen()
接口打开我们的 libiot_sdk.so
这样的情况, 那么在编译SDK和使用它的应用程序的时候, 就需要写成例如
$(TARGET): $(OBJS)
$(CC) -o $@ $^ -liot_sdk -liot_hal -liot_tls -lpthread -lrt
的这个样子
不论是链接静态库, 还是链接动态库, 还是使用 dlopen()
等运行时动态加载的方式使用SDK, 应用程序链接的时候都请确保按照上述顺序编写链接指令。
获取动态链接库形态的SDK编译产物
由于C-SDK大部分情况下运行在非Linux的嵌入式操作系统上, 例如AliOS Things
, 或者FreeRTOS
等。
而这些操作系统并无Linux的动态链接库概念, 所以默认情况下SDK都是以静态库(libiot_sdk.a
+ libiot_hal.a
+ libiot_tls.a
)的方式输出。
可以用如下的修改方法调整默认的输出形态, 将SDK的编译产物从静态库的方式改成动态库。
获取libiot_sdk.so
代替libiot_sdk.a
。
以默认的 config.ubuntu.x86
配置文件为例, 如下的修改可以告诉构建系统要产生动态库形态的构建产物。
--- a/src/board/config.ubuntu.x86
+++ b/src/board/config.ubuntu.x86
@@ -1,6 +1,5 @@
CONFIG_ENV_CFLAGS += \
-Os -Wall \
- -g3 --coverage \
-D_PLATFORM_IS_LINUX_ \
-D__UBUNTU_SDK_DEMO__ \
@@ -19,6 +18,7 @@ CONFIG_ENV_CFLAGS += \
-DCONFIG_MQTT_RX_MAXLEN=5000 \
-DCONFIG_MBEDTLS_DEBUG_LEVEL=0 \
+CONFIG_LIB_EXPORT := dynamic
ifneq (Darwin,$(strip $(shell uname)))
CONFIG_ENV_CFLAGS += -rdynamic
- 改动点1: 确保
CFLAGS
中没有-g3 --coverage
这样的编译选项。 - 改动点2: 新增一行
CONFIG_LIB_EXPORT := dynamic
。 - 改动点3: 重新运行
make reconfig
选择刚才修改到的config.ubuntu.x86
配置文件, 或者被定制的config文件,然后以make all
而不是make
的方式来编译。
按照如上改法, make all
之后在 output/release/lib/libiot_sdk.so
就可以获取动态库形态的SDK了, 其内容和默认的 libiot_sdk.a
是一致的。
$ ls output/release/lib/*.so
output/release/lib/libiot_sdk.so
获取libiot_hal.so
代替libiot_hal.a
。
修改 wrappers/iot.mk
, 新增如下这行。
LIBSO_TARGET := libiot_hal.so
然后运行:
make reconfig
make all
之后便可以在 output/release/lib/libiot_hal.so
得到动态库形式的HAL参考实现的分库,其内容和默认的 libiot_hal.a
是一致的。
获取libiot_tls.so
代替libiot_tls.a
。
修改 external_libs/mbedtls/iot.mk
, 新增如下这行。
LIBSO_TARGET := libiot_tls.so
然后运行:
make reconfig
make all
之后便可以在output/release/lib/libiot_tls.so
得到动态库形式的TLS参考实现的分库,其内容和默认的 libiot_tls.a
是一致的。
TLS/SSL连接错误
-0x7880/-30848/MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY
解释
云端把SSL连接断开了:The peer notified us that the connection is going to be closed
可能的原因和解决建议
- 设备端数据连接过于频繁, 触发云端限流, 断开设备
- 建议关闭设备, 等待一段时间(5分钟以后)再发起连接重试,观察错误仍会出现
- 有多个设备使用相同的productKey和deviceName与云端建立连接,导致被云端踢下线
- 建议检查当前使用的设备证书(ProductKey、DeviceName、DeviceSecret)是否可能被他人使用
- 设备端保活出错, 没有及时发送 MQTT ping packet,或者被发送了没有及时到达云端
- 建议用抓包等方式确认心跳包有成功发出或者观察有没有收到来自服务端的 MQTT ping response
- 如果一次都不能连接成功,可以考虑是不是大小端字节序不匹配
- 目前C-SDK 默认是适配小端设备, 如果需在大端硬件上工作,请添加全局编译选项
REVERSED
- 目前C-SDK 默认是适配小端设备, 如果需在大端硬件上工作,请添加全局编译选项
-0x7800/-30720/MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED
解释
认证错误:Verification of our peer failed
可能的原因和解决建议
- 证书错误
- 如果使用官方C-SDK对接, 证书固化在SDK内部, 不会出现. 若自行对接, 则需检查使用的证书是否和阿里云官方证书匹配
- 日常环境SSL域名校验错误
- 如果出错时, 连接的是日常环境, 则考虑日常不支持SSL域名校验, 请将
FORCE_SSL_VERIFY
的编译选项定义去掉
- 如果出错时, 连接的是日常环境, 则考虑日常不支持SSL域名校验, 请将
-0x7200/-29184/MBEDTLS_ERR_SSL_INVALID_RECORD
解释
收到非法数据:An invalid SSL record was received
可能的原因和解决建议
- TCP/IP协议栈收到的数据包出错, 需要排查协议栈方面问题
- SSL所运行的线程栈被设置的过小, 需调整线程栈大小
- SSL被配置的最大报文长度太小, 当网络报文长度超过该数值时, 则可能出现0x7200错误
- 可调整
MBEDTLS_SSL_MAX_CONTENT_LEN
的值, 重新编译再试 MBEDTLS_SSL_MAX_CONTENT_LEN
的值, 目前已知最小不能小于4096
- 可调整
-0x2700/-9984/MBEDTLS_ERR_X509_CERT_VERIFY_FAILED
解释
证书错误:Certificate verification failed, e.g. CRL, CA or signature check failed
可能的原因和解决建议
- 证书不匹配
- 若未使用官方C-SDK对接,请检查证书是否和阿里云官网提供下载的一致
- 时钟不对
- 确认系统时间是否准确,系统时间不对(例如默认的1970-01-01),也会导致证书校验失败
-0x0052/-82/MBEDTLS_ERR_NET_UNKNOWN_HOST
解释
DNS域名解析错误:Failed to get an IP address for the given hostname
可能的原因和解决建议
- 大概率是设备端当前网络故障, 无法访问公网
- 如果是WiFi设备, 检查其和路由器/热点之间的连接状况, 以及上联路由器是否可以正常访问公网
- 需要通过类似
res_init()
之类的调用强制C库刷新DNS解析文件- 在Linux系统上, 域名解析的系统调用
getaddrinfo()
的工作是依赖域名解析文件/etc/resolv.conf
- 对某些嵌入式Linux, 可能会有
libc
库读取过时的/etc/resolv.conf
问题 - 对于这类系统, 域名解析请求不论是早于还是晚于域名解析文件的更新, 都会读到过时的信息, 进而造成域名解析失败
- 在Linux系统上, 域名解析的系统调用
这种现象产生的原因是DNS文件的更新晚于MQTT的域名解析请求, 这样
getaddrinfo()
系统调用就会得到一个EAI_AGAIN
错误, 如果不通过res_init()
, C库中的getaddrinfo()
即使被重试逻辑调用也仍然读取过时的DNS文件, 并继续得到EAI_AGAIN
错误
例如, 可以改动 HAL_TLS_mbedtls.c
#include <arpa/nameser.h>
#include <resolv.h>
...
...
if ((ret = getaddrinfo(host, port, &hints, &addr_list)) != 0) {
if (ret == EAI_AGAIN)
res_init();
return (MBEDTLS_ERR_NET_UNKNOWN_HOST);
}
以上只是一个示意的改法, res_init()
本身也是一个过时的函数, 所以不建议进入SDK的官方代码, 用户可以酌情加在合适的位置
-0x0044/-68/MBEDTLS_ERR_NET_CONNECT_FAILED
解释
socket连接失败:The connection to the given server / port failed
可能的原因和解决建议
- TCP连接失败
- 请确认连接的目标IP地址/域名, 以及端口号是否正确
-0x0043/-67/MBEDTLS_ERR_NET_BUFFER_TOO_SMALL
解释
SSL报文缓冲区过短:Buffer is too small to hold the data
可能的原因和解决建议
- SSL被配置的最大报文长度太小
- 可调整
MBEDTLS_SSL_MAX_CONTENT_LEN
的值, 重新编译再试 MBEDTLS_SSL_MAX_CONTENT_LEN
的值, 目前已知最小不能小于4096
- 可调整
-0x0042/-66/MBEDTLS_ERR_NET_SOCKET_FAILED
解释
创建socket失败:Failed to open a socket
可能的原因和解决建议
- 系统可用的socket可能已全部被申请, 在有些平台上, 能被开启的socket数量, 有上限的
- 检查当前的流程是否有socket的泄漏, 有些socket使用完后没有close
- 如果流程正常, 确需同时建立多个socket, 请调整socket的个数上限
MQTT连接
-35/MQTT_CONNACK_BAD_USERDATA_ERROR
解释
发起MQTT协议中的Connect操作失败:Connect request failed with the server returning a bad userdata error
可能的原因和解决建议
- 使用了错误的设备证书(ProductKey、DeviceName、DeviceSecret)
- 建议检查 productKey/deviceName/deviceSecret 是否正确并且是同一套
- 设备证书(ProductKey、DeviceName、DeviceSecret)传入的参数不正确
- 建议检查C函数的传参过程
- 设备证书(ProductKey、DeviceName、DeviceSecret)被禁用
- 若经检查确系禁用, 请在控制台或是使用服务端相应API解除禁用
-37/MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR
解释
云端认为设备权限不足而拒绝设备端的连接请求:CONNACK
报文中的错误码是 2
可能的原因和解决建议
- MQTT的Connect报文参数中, clientId的上报内容和协议预期不符, 这通常发生在不使用官方SDK而使用第三方MQTT自行对接时
- 建议检查在控制台创建当前设备证书(ProductKey、DeviceName、DeviceSecret)的账号, 是否有权限, 如是否有发生欠费等
-42/MQTT_PUSH_TO_LIST_ERROR
解释
订阅或是发布(QoS1)太多太快, 导致SDK内部队列满了而出错
可能的原因和解决建议
- 如果是订阅过程中发生的错误, 说明当前订阅使用的队列长度不够
- 可以考虑调整
IOTX_MC_SUB_NUM_MAX
的值
- 可以考虑调整
- 如果是发布过程中发生的错误, 可能是发送的频率太快, 或是网络状态不佳
- 可以考虑使用QoS0来发布
- 可以考虑调整
IOTX_MC_REPUB_NUM_MAX
的值
什么是域名直连, 如何开启
C-SDK 的 2.0 以上版本, MQTT连接有两种方式, 一种是认证模式, 一种是域名直连模式
- 认证模式是设备先用 HTTPS 方式访问类似
https://iot-auth.cn-shanghai.aliyuncs.com:443
的地址, 进行鉴权 - 鉴权通过之后, 再用 MQTT 方式连接到类似 public.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883 的 MQTT 服务器地址
- 域名直连模式是设备直接用 MQTT 方式连接到类似 ${productKey}.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883的 MQTT 服务器地址
- 这样不需要访问 HTTPS+MQTT 两台服务器才建立连接, 更快建立连接, 耗费的端上资源也更少
2.0 以上的版本, 默认已经开启了直连模式, 如果配置文件 make.settings
不是默认的状态了, 那么
打开 make.setting
文件, 在文件尾部写入 FEATURE_MQTT_DIRECT = y
, 然后运行 make
命令重新编译, 即可确保开启直连模式
MQTT协议版本是多少
C-SDK 的 2.0 以上版本, 封装的MQTT协议版本号是 3.1.1
例程 mqtt-example 连接上线后会很快下线, 如何修改可以一直处于在线状态
mqtt-example 例程本身的逻辑是发送一次消息后会自动退出
若需要此例程保持长期在线, 执行命令时加上 "loop" 参数即可,例如:
.output/release/bin/mqtt-example loop
当您这样做时, 请确保使用自己申请的 productKey/deviceName/deviceSecret 覆盖代码中的设备身份信息后重新编译例程
因为官方SDK的代码中默认编写的是一台公用设备的信息, 有其他人同时使用时, 您会被踢下线, 同一组设备信息只能同时在线一个连接
如何持续的接收MQTT消息
需要循环多次的调用 IOT_MQTT_Yield 函数, 在其内部会自动的维持心跳和接收云端下发的MQTT消息
可以参考 examples 目录下, mqtt-example.c 里面的 while 循环部分
心跳和重连
心跳的时间间隔如何设置
在 IOT_MQTT_Construct 的入参中可以设置 keepalive_interval_ms
的值, C-SDK用这个值作为心跳间隔时间
keepalive_interval_ms 的取值范围是 60000 - 300000, 即最短心跳间隔为1分钟, 最长心跳间隔为5分钟
设备端是如何侦测到需要重连(reconnect)的
设备端C-SDK会在 keepalive_interval_ms
时间间隔过去之后, 再次发送 MQTT ping request, 并等待 MQTT ping response
如果在接下来的下一个 keepalive_interval_ms
时间间隔内, 没有收到对应的 ping response
或是在进行报文的上行发送(send)或者下行接收(recv)时发生异常, 则 C-SDK 就认为此时网络断开了, 需要进行重连
设备端的重连机制是什么
C-SDK 的重连动作是内部触发, 无需用户显式干预. 对于使用基础版的用户, 需要时常调用IOT_MQTT_Yield 函数将 CPU 交给SDK, 重连就在其中发生
重连如果不成功, 会在间隔一段时间之后持续重试, 直到再次连接成功为止
相邻的两次重连之间的间隔时间是指数退避+随机数的关系, 例如间隔1s+随机秒数, 间隔2s+随机秒数, 间隔4s+随机秒数, 间隔8s+随机秒数... 直到间隔达到了间隔上限(默认60s)
关于 IOT_MQTT_Yield
IOT_MQTT_Yield 的作用
IOT_MQTT_Yield的作用主要是给SDK机会去尝试从网络上接收数据
因此在需要接收数据时(subscribe/unsubscribe之后, publish之后, 以及希望收到云端下推数据时),都需要主动调用该函数
IOT_MQTT_Yield 参数 timeout 的意义
IOT_MQTT_Yield 会阻塞住 timeout 指定的时间(单位毫秒)去尝试接收数据, 直到超出这个时间, 才会返回调用它的函数
IOT_MQTT_Yield 与 HAL_SleepMs 的区别
都会阻塞一段时间才返回, 但是IOT_MQTT_Yield实质是去从网络上接收数据
而HAL_SleepMs则是什么也不做, 单纯等待入参指定的时间间隔过去后返回
订阅相关
如果订阅了多个topic, 调用一次IOT_MQTT_Yield, 可能接收到多个topic的消息吗
调用一次 IOT_MQTT_Yield, 如果多个topic都被订阅成功并且都有数据下发, 则可以一次性接收到来自多个topic的消息
什么情况下会发生订阅超时
- 调用IOT_MQTT_Construct 和云端建立MQTT连接时, 其入参中可以设置请求超时时间
request_timeout_ms
的值 - 如果两倍
request_timeout_ms
时间过去, 仍未收到来自云端的SUBACK
消息, 则会触发订阅(Subscribe)超时 - 超时的事件会通过 IOT_MQTT_Construct 入参中设置的
event_handle
回调函数通知到用户 - 在调用IOT_MQTT_Subscribe 之后, 需要尽快执行 IOT_MQTT_Construct 以接收SUBACK, 请勿使用 HAL_SleepMs
发布相关
发布(Publish)的消息最长是多少, 超过会怎么样
- C-SDK的代码上来说, MQTT的消息报文长度, 受限于 IOT_MQTT_Construct 入参中
write_buf
和read_buf
的大小 - 从云端协议上来说, MQTT消息报文长度不能超过256KB, 具体查阅使用限制 为准
- 如果实际上报消息长度大于C-SDK的限制, 消息会被丢掉
被发布消息payload格式是怎么样的
阿里云物联网平台并没有指定pub消息的payload格式
需要客户根据应用场景制定自己的协议, 然后以JSON格式或其它格式, 放到pub消息载体里面传给服务端
消息推送
物联网平台云端是否一有消息就立刻推送给订阅的设备而不做保存?消息一到达云端, 就会分发给不同的设备订阅者, 云端服务器不进行保存, 目前不支持 MQTT 协议中的 will 和 retain 特性
MQTT长连接时, 云端如何侦测到设备离线的
云端会根据用户调用 IOT_MQTT_Construct 时传入的 keepalive_interval_ms
, 作为心跳间隔, 等待 MQTT ping request
如果在约定的心跳间隔过去之后, 最多再等5秒钟, 若还是没有收到 MQTT ping request, 则认为设备离线
CoAP上云问题
认证超时失败, 目前总结下来分为下述两种情况
连接失败的时候, ssl->state为MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC的情况
在出现问题的一次测试中通过tcpdump进行抓包,结果通过wireshark展示如下图。其中client(ip地址为30.5.88.208)发出了握手数据包(包括client key exchange, change cipher spec, encrypted handshake message),但是服务端并没有回复change cipher spec的数据包,从而导致coap连云卡在这一步. 卡在这一步后,但如果等待2s后没有等到数据,客户端会再进行两次尝试超时等待(4s、8s);如果3次都等不到服务端发来的change cipher spec的数据包, 则退出handshake过程,导致连接失败由上分析可知,这个问题的根因是在服务端。
连接失败的时候, ssl->state为MBEDTLS_SSL_HANDSHAKE_OVER的情况
CoAP上云连接的云端URI是什么
- 在调用IOT_CoAP_Init 的时候, 可以设置其参数
iotx_coap_config_t
里面的p_url
- 如果
p_url
值为NULL, 则C-SDK会自动使用IOTX_ONLINE_DTLS_SERVER_URL
这个宏所定义的默认URL
#define IOTX_ONLINE_DTLS_SERVER_URL "coaps://%s.iot-as-coap.cn-shanghai.aliyuncs.com:5684"
- 其中
%s
是使用p_devinfo
里面的product_key
, 所以请确保在初始化iotx_coap_config_t
的时候一定要对p_devinfo
赋值
IOT_CoAP_SendMessage 发送的消息必须是JSON格式吗, 如果不是JSON会出现什么错误
- 目前, 除了支持JSON格式外, 也可以支持CBOR格式
- 因为是与云端通信, 需要使用指定格式, 否则可能会出现无法解析的问题
关于 IOT_CoAP_Yield
如何设置 IOT_CoAP_Yield 处理结果最大等待时间?
目前默认设置是2000ms, 可以修改 COAP_WAIT_TIME_MS
这个宏进行调整
HTTP上云问题
认证连接
HTTPS进行设备认证时, Server会返回的错误码及其含义
- 10000: common error(未知错误)
- HTTPS报文是有一定格式要求, 必须符合要求server才能支持
ContentType
只支持"application/json"- 只支持HTTPS
- 只支持POST方法
- 40000: request too many(请求次数过多, 流控限制)
- 同一个设备在一天内的认证次数是有限制的
- 解决方法:每次认证获得的token是有48小时有效期的, 过期前可以反复使用, 无需每次都去认证获取新的token
- 400: authorized failure(认证失败)
- 服务器认为鉴权参数是不合法的,鉴权失败
- 解决方法:检查
IOTX_PRODUCT_KEY
,IOTX_DEVICE_NAME
,IOTX_DEVICE_SECRET
,IOTX_DEVICE_ID
是不是从控制台获得的正确参数
TLS连接问题
设备端TLS密码算法
目前C-SDK连接云端用到的默认TLS算法是:TLS-RSA-WITH-AES-256-CBC-SHA256
云端TLS密码算法
目前阿里云IoT平台支持的TLS算法清单如下:
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
TLS_ECDHE_RSA_WITH_RC4_128_SHA
SSL_RSA_WITH_RC4_128_SHA
TLS_ECDH_ECDSA_WITH_RC4_128_SHA
TLS_ECDH_RSA_WITH_RC4_128_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_RC4_128_MD5
TLS_EMPTY_RENEGOTIATION_INFO_SCSV